diff --git a/.github/labeler.yml b/.github/labeler.yml index cab1b5438..e41e05a14 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -25,6 +25,15 @@ - modules/programs/neovim.nix - tests/modules/programs/neovim/**/* +"program: firefox": + - changed-files: + - any-glob-to-any-file: + - modules/programs/firefox/**/* + - tests/modules/programs/firefox/**/* + - modules/misc/mozilla-messaging-hosts.nix + - modules/programs/floorp.nix + - modules/programs/librewolf.nix + "shell": - changed-files: - any-glob-to-any-file: diff --git a/.github/workflows/github_pages.yml b/.github/workflows/github_pages.yml index 4e10f9ccb..279c8763a 100644 --- a/.github/workflows/github_pages.yml +++ b/.github/workflows/github_pages.yml @@ -11,10 +11,10 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v30 + - uses: cachix/install-nix-action@v31 with: nix_path: nixpkgs=channel:nixos-unstable - - uses: cachix/cachix-action@v15 + - uses: cachix/cachix-action@v16 with: name: nix-community authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index db71dca7b..6a698c329 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v30 + - uses: cachix/install-nix-action@v31 with: nix_path: nixpkgs=channel:nixos-unstable - run: | @@ -25,7 +25,5 @@ jobs: - run: nix-shell --show-trace . -A install - run: yes | home-manager -I home-manager=. uninstall - run: nix-shell -j auto --show-trace --arg enableBig false --pure tests -A run.all - # Somebody please help us fix the macos tests. - if: matrix.os != 'macos-latest' env: GC_INITIAL_HEAP_SIZE: 4294967296 diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml index 9b0e4b443..5e6b9c243 100644 --- a/.github/workflows/update-flake.yml +++ b/.github/workflows/update-flake.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - name: Install Nix - uses: cachix/install-nix-action@v30 + uses: cachix/install-nix-action@v31 - name: Update flake.lock uses: DeterminateSystems/update-flake-lock@v24 with: diff --git a/docs/home-manager.1 b/docs/home-manager.1 index 46ee43033..34a40f753 100644 --- a/docs/home-manager.1 +++ b/docs/home-manager.1 @@ -45,6 +45,7 @@ .Op Fl -keep-failed .Op Fl -keep-going .Op Bro Fl L | Fl -print-build-logs Brc +.Op Fl -log-format .Op Fl -show-trace .Op Fl -(no-)substitute .Op Fl -no-out-link @@ -335,6 +336,13 @@ when building from a flake\&. .RE .Pp +.It Cm Fl -log-format Ar format +.RS 4 +Passed on to +\fBnix-build\fR(1)\&. +.RE +.Pp + .It Cm Fl -show-trace .RS 4 Passed on to diff --git a/docs/manual/installation/nixos.md b/docs/manual/installation/nixos.md index 6c9807ee8..b72d9ad33 100644 --- a/docs/manual/installation/nixos.md +++ b/docs/manual/installation/nixos.md @@ -34,6 +34,31 @@ to your system `configuration.nix` file, which will introduce a new NixOS option called `home-manager.users` whose type is an attribute set that maps user names to Home Manager configurations. +Alternatively, home-manager installation can be done declaratively through configuration.nix using the following syntax: +```nix +{ config, pkgs, lib, ... }: + +let + home-manager = builtins.fetchTarball https://github.com/nix-community/home-manager/archive/release-24.11.tar.gz; +in +{ + imports = + [ + (import "${home-manager}/nixos") + ]; + + users.users.eve.isNormalUser = true; + home-manager.users.eve = { pkgs, ... }: { + home.packages = [ pkgs.atool pkgs.httpie ]; + programs.bash.enable = true; + + # The state version is required and should stay at the version you + # originally installed. + home.stateVersion = "24.11"; + }; +} +``` + For example, a NixOS configuration may include the lines ``` nix @@ -42,9 +67,15 @@ home-manager.users.eve = { pkgs, ... }: { home.packages = [ pkgs.atool pkgs.httpie ]; programs.bash.enable = true; - # The state version is required and should stay at the version you - # originally installed. - home.stateVersion = "24.11"; + # This value determines the Home Manager release that your configuration is + # compatible with. This helps avoid breakage when a new Home Manager release + # introduces backwards incompatible changes. + # + # You should not change this value, even if you update Home Manager. If you do + # want to update the value, then make sure to first check the Home Manager + # release notes. + home.stateVersion = "24.05"; # Please read the comment before changing. + }; ``` @@ -123,3 +154,4 @@ you create. This contains the system's NixOS configuration. Once installed you can see [Using Home Manager](#ch-usage) for a more detailed description of Home Manager and how to use it. + diff --git a/docs/manual/nix-flakes/flake-parts.md b/docs/manual/nix-flakes/flake-parts.md index 6b05c77f2..b314bef3c 100644 --- a/docs/manual/nix-flakes/flake-parts.md +++ b/docs/manual/nix-flakes/flake-parts.md @@ -22,7 +22,7 @@ you may wish to import Home Manager's flake module, inputs.home-manager.flakeModules.home-manager ]; flake = { - # Define `homeManagerModules`, `homeConfigurations`, + # Define `homeModules`, `homeConfigurations`, # `nixosConfigurations`, etc here }; # See flake.parts for more features, such as `perSystem` @@ -30,10 +30,10 @@ you may wish to import Home Manager's flake module, } ``` -The flake module defines the `flake.homeManagerModules` and `flake.homeConfigurations` +The flake module defines the `flake.homeModules` and `flake.homeConfigurations` options, allowing them to be properly merged if they are defined in multiple modules. -If you are only defining `homeManagerModules` and/or `homeConfigurations` once in a +If you are only defining `homeModules` and/or `homeConfigurations` once in a single module, flake-parts should work fine without importing `flakeModules.home-manager`. diff --git a/flake-module.nix b/flake-module.nix index 59091dcde..cc5f1551a 100644 --- a/flake-module.nix +++ b/flake-module.nix @@ -4,7 +4,7 @@ in { options = { flake = flake-parts-lib.mkSubmoduleOptions { homeConfigurations = mkOption { - type = types.lazyAttrsOf types.deferredModule; + type = types.lazyAttrsOf types.raw; default = { }; description = '' Instantiated Home Manager configurations. @@ -14,12 +14,12 @@ in { that you can reference them in this or another flake's `homeConfigurations`. ''; }; - homeManagerModules = mkOption { - type = types.lazyAttrsOf types.unspecified; + homeModules = mkOption { + type = types.lazyAttrsOf types.deferredModule; default = { }; apply = mapAttrs (k: v: { _class = "homeManager"; - _file = "${toString moduleLocation}#homeManagerModules.${k}"; + _file = "${toString moduleLocation}#homeModules.${k}"; imports = [ v ]; }); description = '' diff --git a/flake.lock b/flake.lock index 6ca2bd080..c0e3b5c70 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1739020877, - "narHash": "sha256-mIvECo/NNdJJ/bXjNqIh8yeoSjVLAuDuTUzAo7dzs8Y=", + "lastModified": 1742669843, + "narHash": "sha256-G5n+FOXLXcRx+3hCJ6Rt6ZQyF1zqQ0DL0sWAMn2Nk0w=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a79cfe0ebd24952b580b1cf08cd906354996d547", + "rev": "1e5b653dff12029333a6546c11e108ede13052eb", "type": "github" }, "original": { diff --git a/home-manager/completion.bash b/home-manager/completion.bash index d59c8a118..bc11315c8 100644 --- a/home-manager/completion.bash +++ b/home-manager/completion.bash @@ -300,7 +300,7 @@ _home-manager_completions () Options=( "-f" "--file" "-b" "-A" "-I" "-h" "--help" "-n" "--dry-run" "-v" \ "--verbose" "--cores" "--debug" "--impure" "--keep-failed" \ "--keep-going" "-j" "--max-jobs" "--no-substitute" "--no-out-link" \ - "-L" "--print-build-logs" \ + "-L" "--print-build-logs" "--log-format" \ "--show-trace" "--flake" "--substitute" "--builders" "--version" \ "--update-input" "--override-input" "--experimental-features" \ "--extra-experimental-features" "--refresh") diff --git a/home-manager/completion.fish b/home-manager/completion.fish index 3781d3a71..6dc09510d 100644 --- a/home-manager/completion.fish +++ b/home-manager/completion.fish @@ -61,6 +61,7 @@ complete -c home-manager -x -s j -l "max-jobs" -d "Max number of build jobs in p complete -c home-manager -x -l "option" -d "Set Nix configuration option" complete -c home-manager -x -l "builders" -d "Remote builders" complete -c home-manager -f -s L -l "print-build-logs" -d "Print full build logs on standard error" +complete -c home-manager -x -l "log-format" -d "Set the format of log output" complete -c home-manager -f -l "show-trace" -d "Print stack trace of evaluation errors" complete -c home-manager -f -l "substitute" complete -c home-manager -f -l "no-substitute" diff --git a/home-manager/completion.zsh b/home-manager/completion.zsh index 43cc9bdb9..815e432e9 100644 --- a/home-manager/completion.zsh +++ b/home-manager/completion.zsh @@ -21,6 +21,7 @@ _arguments \ '--option[option]:NAME VALUE:()' \ '--builders[builders]:SPEC:()' \ '(-L --print-build-logs)'{--print-build-logs,-L}'[print build logs]' \ + '--log-format[log format]:FORMAT:()' \ '--show-trace[show trace]' \ '--override-input[override flake input]:NAME VALUE:()' \ '--update-input[update flake input]:NAME:()' \ @@ -63,6 +64,7 @@ case "$state" in '--no-out-link[no out link]' \ '--no-substitute[no substitute]' \ '--option[option]:NAME VALUE:()' \ + '--log-format[log format]:FORMAT:()' \ '--show-trace[show trace]' \ '--substitute[substitute]' \ '--builders[builders]:SPEC:()' \ diff --git a/home-manager/default.nix b/home-manager/default.nix index 50fda77e5..6b594c4fd 100644 --- a/home-manager/default.nix +++ b/home-manager/default.nix @@ -16,12 +16,12 @@ let in runCommand "home-manager" { preferLocalBuild = true; nativeBuildInputs = [ gettext ]; - meta = with lib; { + meta = { mainProgram = "home-manager"; description = "A user environment configurator"; - maintainers = [ maintainers.rycee ]; - platforms = platforms.unix; - license = licenses.mit; + maintainers = [ lib.maintainers.rycee ]; + platforms = lib.platforms.unix; + license = lib.licenses.mit; }; } '' install -v -D -m755 ${./home-manager} $out/bin/home-manager diff --git a/home-manager/home-manager b/home-manager/home-manager index e64bb884d..ddd9879b0 100644 --- a/home-manager/home-manager +++ b/home-manager/home-manager @@ -907,6 +907,7 @@ function doHelp() { echo " -j, --max-jobs NUM" echo " --option NAME VALUE" echo " -L, --print-build-logs" + echo " --log-format FORMAT" echo " --show-trace" echo " --(no-)substitute" echo " --no-out-link Do not create a symlink to the output path" @@ -1036,7 +1037,7 @@ while [[ $# -gt 0 ]]; do PASSTHROUGH_OPTS+=("$opt" "$1" "$2") shift 2 ;; - -j|--max-jobs|--cores|--builders) + -j|--max-jobs|--cores|--builders|--log-format) [[ -v 1 && $1 != -* ]] || errMissingOptArg "$opt" PASSTHROUGH_OPTS+=("$opt" "$1") shift diff --git a/home-manager/po/zh_Hant.po b/home-manager/po/zh_Hant.po index bf113567a..60520bcda 100644 --- a/home-manager/po/zh_Hant.po +++ b/home-manager/po/zh_Hant.po @@ -8,21 +8,21 @@ msgstr "" "Project-Id-Version: Home Manager\n" "Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n" "POT-Creation-Date: 2025-01-03 09:09+0100\n" -"PO-Revision-Date: 2024-02-16 22:01+0000\n" -"Last-Translator: Robert Helgesson \n" -"Language-Team: Chinese (Traditional) \n" +"PO-Revision-Date: 2025-03-07 18:58+0000\n" +"Last-Translator: 807 \n" +"Language-Team: Chinese (Traditional Han script) \n" "Language: zh_Hant\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.4\n" +"X-Generator: Weblate 5.10.3-dev\n" #. translators: For example: "home-manager: missing argument for --cores" #: home-manager/home-manager:16 msgid "%s: missing argument for %s" -msgstr "" +msgstr "%s: 缺少參數 %s" #: home-manager/home-manager:69 msgid "No configuration file found at %s" @@ -36,6 +36,8 @@ msgid "" "Keeping your Home Manager %s in %s is deprecated,\n" "please move it to %s" msgstr "" +"保持你的 Home Manager 在 %s 中,%s 已被拋棄,\n" +"請將它移動到 %s" #: home-manager/home-manager:97 msgid "No configuration file found. Please create one at %s" @@ -43,14 +45,14 @@ msgstr "未找到配置檔案。請在 %s 處建立一份" #: home-manager/home-manager:112 msgid "Home Manager not found at %s." -msgstr "" +msgstr "在 %s 中找不到 Home Manager。" #. translators: This message will be seen by very few users that likely are familiar with English. So feel free to leave this untranslated. #: home-manager/home-manager:120 msgid "" "The fallback Home Manager path %s has been deprecated and a file/directory " "was found there." -msgstr "" +msgstr "備用的 Home Manager 路徑 %s 已被拋棄,但一個檔案/資料夾在這被找到。" #. translators: This message will be seen by very few users that likely are familiar with English. So feel free to leave this untranslated. #: home-manager/home-manager:123 @@ -73,6 +75,23 @@ msgid "" "\n" " $ rm -r \"%s\"" msgstr "" +"要消除這個警告,請做以下其中一步。\n" +"\n" +"1. 告訴Home Manager去使用路徑,例如加入\n" +"\n" +" { programs.home-manager.path = \"%s\"; }\n" +"\n" +" 到你的配置中。\n" +"\n" +" 如果你想要直接引入Home Manager, 請你使用 `path` 參數r\n" +"\n" +" pkgs.callPackage /path/to/home-manager-package { path = \"%s\"; }\n" +"\n" +" 當呼叫 Home Manager 模組。\n" +"\n" +"2. 刪除無效的路徑\n" +"\n" +" $ rm -r \"%s\"" #: home-manager/home-manager:151 msgid "Sanity checking Nix" @@ -80,7 +99,7 @@ msgstr "正在進行 Nix 完整性檢查" #: home-manager/home-manager:171 msgid "Could not find suitable profile directory, tried %s and %s" -msgstr "" +msgstr "找不到合適的 profile 目錄,已經嘗試 %s 和 %s" #. translators: Here "flake" is a noun that refers to the Nix Flakes feature. #: home-manager/home-manager:226 @@ -98,11 +117,11 @@ msgstr "執行 ‘%s --help’ 獲取用法幫助" #: home-manager/home-manager:332 home-manager/home-manager:437 msgid "The file %s already exists, leaving it unchanged..." -msgstr "" +msgstr "檔案 %s 已經存在,不更改它..." #: home-manager/home-manager:334 home-manager/home-manager:439 msgid "Creating %s..." -msgstr "" +msgstr "創建 %s 中..." #: home-manager/home-manager:481 msgid "Creating initial Home Manager generation..." @@ -163,11 +182,11 @@ msgstr "未知的 “news.display” 設定項 “%s”。" #: home-manager/home-manager:600 #, sh-format msgid "Please set the $EDITOR or $VISUAL environment variable" -msgstr "" +msgstr "請設定 $EDITOR 或 $VISUAL 環境變數" #: home-manager/home-manager:618 msgid "Cannot run build in read-only directory" -msgstr "無法在只讀目錄中執行構建" +msgstr "無法在唯讀目錄中執行構建" #: home-manager/home-manager:699 msgid "No generation with ID %s" diff --git a/modules/accounts/calendar.nix b/modules/accounts/calendar.nix index 86f1b38c5..d71d4dff3 100644 --- a/modules/accounts/calendar.nix +++ b/modules/accounts/calendar.nix @@ -1,8 +1,6 @@ -{ config, lib, pkgs, ... }: - -with lib; - +{ config, lib, ... }: let + inherit (lib) mkOption types; cfg = config.accounts.calendar; @@ -70,7 +68,7 @@ let }; }; - calendarOpts = { name, config, ... }: { + calendarOpts = { name, ... }: { options = { name = mkOption { type = types.str; @@ -125,7 +123,7 @@ in { type = types.str; example = ".calendar"; apply = p: - if hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}"; + if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}"; description = '' The base directory in which to save calendars. May be a relative path, in which case it is relative the home @@ -144,15 +142,15 @@ in { description = "List of calendars."; }; }; - config = mkIf (cfg.accounts != { }) { + config = lib.mkIf (cfg.accounts != { }) { assertions = let - primaries = - catAttrs "name" (filter (a: a.primary) (attrValues cfg.accounts)); + primaries = lib.catAttrs "name" + (lib.filter (a: a.primary) (lib.attrValues cfg.accounts)); in [{ - assertion = length primaries <= 1; + assertion = lib.length primaries <= 1; message = "Must have at most one primary calendar account but found " - + toString (length primaries) + ", namely " - + concatStringsSep ", " primaries; + + toString (lib.length primaries) + ", namely " + + lib.concatStringsSep ", " primaries; }]; }; } diff --git a/modules/accounts/contacts.nix b/modules/accounts/contacts.nix index d00f5d071..b5d93f21f 100644 --- a/modules/accounts/contacts.nix +++ b/modules/accounts/contacts.nix @@ -1,8 +1,7 @@ -{ config, lib, pkgs, ... }: - -with lib; +{ config, lib, ... }: let + inherit (lib) mkOption types; cfg = config.accounts.contact; @@ -78,7 +77,7 @@ let }; }; - contactOpts = { name, config, ... }: { + contactOpts = { name, ... }: { options = { name = mkOption { type = types.str; @@ -114,7 +113,7 @@ in { basePath = mkOption { type = types.str; apply = p: - if hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}"; + if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}"; description = '' The base directory in which to save contacts. May be a relative path, in which case it is relative the home diff --git a/modules/accounts/email.nix b/modules/accounts/email.nix index e8cc708ed..2395f7e39 100644 --- a/modules/accounts/email.nix +++ b/modules/accounts/email.nix @@ -1,8 +1,7 @@ -{ config, lib, pkgs, ... }: - -with lib; +{ config, lib, ... }: let + inherit (lib) mkDefault mkIf mkOption types; cfg = config.accounts.email; @@ -49,7 +48,7 @@ let default = '' -- ''; - example = literalExpression '' + example = lib.literalExpression '' ~*~*~*~*~*~*~*~*~*~*~*~ ''; description = '' @@ -60,7 +59,7 @@ let command = mkOption { type = with types; nullOr path; default = null; - example = literalExpression '' + example = lib.literalExpression '' pkgs.writeScript "signature" "echo This is my signature" ''; description = "A command that generates a signature."; @@ -268,10 +267,26 @@ let }; aliases = mkOption { - type = types.listOf (types.strMatching ".*@.*"); + description = "Alternative identities of this account."; default = [ ]; example = [ "webmaster@example.org" "admin@example.org" ]; - description = "Alternative email addresses of this account."; + type = types.listOf (types.oneOf [ + (types.strMatching ".*@.*") + (types.submodule { + options = { + realName = mkOption { + type = types.str; + example = "Jane Doe"; + description = "Name displayed when sending mails."; + }; + address = mkOption { + type = types.strMatching ".*@.*"; + example = "jane.doe@example.org"; + description = "The email address of this identity."; + }; + }; + }) + ]); }; realName = mkOption { @@ -292,7 +307,7 @@ let passwordCommand = mkOption { type = types.nullOr (types.either types.str (types.listOf types.str)); default = null; - apply = p: if isString p then splitString " " p else p; + apply = p: if lib.isString p then lib.splitString " " p else p; example = "secret-tool lookup email me@example.org"; description = '' A command, which when run writes the account password on @@ -391,10 +406,10 @@ let }; }; - config = mkMerge [ + config = lib.mkMerge [ { name = name; - maildir = mkOptionDefault { path = "${name}"; }; + maildir = lib.mkOptionDefault { path = "${name}"; }; } (mkIf (config.flavor == "yandex.com") { @@ -510,7 +525,7 @@ in { default = "${config.home.homeDirectory}/Maildir"; defaultText = "Maildir"; apply = p: - if hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}"; + if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}"; description = '' The base directory for account maildir directories. May be a relative path (e.g. the user setting this value as "MyMaildir"), @@ -529,13 +544,14 @@ in { config = mkIf (cfg.accounts != { }) { assertions = [ (let - primaries = - catAttrs "name" (filter (a: a.primary) (attrValues cfg.accounts)); + primaries = lib.catAttrs "name" + (lib.filter (a: a.primary) (lib.attrValues cfg.accounts)); in { - assertion = length primaries == 1; + assertion = lib.length primaries == 1; message = "Must have exactly one primary mail account but found " - + toString (length primaries) + optionalString (length primaries > 1) - (", namely " + concatStringsSep ", " primaries); + + toString (lib.length primaries) + + lib.optionalString (lib.length primaries > 1) + (", namely " + lib.concatStringsSep ", " primaries); }) ]; }; diff --git a/modules/config/home-cursor.nix b/modules/config/home-cursor.nix index 42c259455..ee8edbbb6 100644 --- a/modules/config/home-cursor.nix +++ b/modules/config/home-cursor.nix @@ -1,13 +1,17 @@ { config, options, lib, pkgs, ... }: -with lib; - let + inherit (lib) + mkEnableOption mkOption mkIf mkMerge mkDefault mkAliasOptionModule types + literalExpression escapeShellArg hm getAttrFromPath any optional; cfg = config.home.pointerCursor; + opts = options.home.pointerCursor; pointerCursorModule = types.submodule { options = { + enable = mkEnableOption "cursor config generation"; + package = mkOption { type = types.package; example = literalExpression "pkgs.vanilla-dmz"; @@ -46,6 +50,14 @@ let ''; }; + dotIcons = { + enable = mkEnableOption '' + `.icons` config generation for {option}`home.pointerCursor` + '' // { + default = true; + }; + }; + hyprcursor = { enable = mkEnableOption "hyprcursor config generation"; @@ -56,6 +68,11 @@ let description = "The cursor size for hyprcursor."; }; }; + + sway = { + enable = mkEnableOption + "sway config generation for {option}`home.pointerCursor`"; + }; }; }; @@ -78,7 +95,7 @@ let }; in { - meta.maintainers = [ maintainers.league ]; + meta.maintainers = [ lib.maintainers.league ]; imports = [ (mkAliasOptionModule [ "xsession" "pointerCursor" "package" ] [ @@ -102,17 +119,6 @@ in { "x11" "defaultCursor" ]) - - ({ ... }: { - warnings = optional (any (x: - getAttrFromPath - ([ "xsession" "pointerCursor" ] ++ [ x ] ++ [ "isDefined" ]) - options) [ "package" "name" "size" "defaultCursor" ]) '' - The option `xsession.pointerCursor` has been merged into `home.pointerCursor` and will be removed - in the future. Please change to set `home.pointerCursor` directly and enable `home.pointerCursor.x11.enable` - to generate x11 specific cursor configurations. You can refer to the documentation for more details. - ''; - }) ]; options = { @@ -120,7 +126,7 @@ in { type = types.nullOr pointerCursorModule; default = null; description = '' - Cursor configuration. Set to `null` to disable. + Cursor configuration. Top-level options declared under this submodule are backend independent options. Options declared under namespaces such as `x11` @@ -139,63 +145,107 @@ in { }; }; - config = mkIf (cfg != null) (mkMerge [ + config = let + # Check if enable option was explicitly defined by the user + enableDefined = any (x: x ? enable) opts.definitions; + + # Determine if cursor configuration should be enabled + enable = if enableDefined then cfg.enable else cfg != null; + in mkMerge [ + (mkIf enable (mkMerge [ + { + assertions = [ + (hm.assertions.assertPlatform "home.pointerCursor" pkgs + lib.platforms.linux) + ]; + + home.packages = [ cfg.package defaultIndexThemePackage ]; + + home.sessionVariables = { + XCURSOR_SIZE = mkDefault cfg.size; + XCURSOR_THEME = mkDefault cfg.name; + }; + + # Set directory to look for cursors in, needed for some applications + # that are unable to find cursors otherwise. See: + # https://github.com/nix-community/home-manager/issues/2812 + # https://wiki.archlinux.org/title/Cursor_themes#Environment_variable + home.sessionSearchVariables.XCURSOR_PATH = + [ "${config.home.profileDirectory}/share/icons" ]; + + # Add cursor icon link to $XDG_DATA_HOME/icons as well for redundancy. + xdg.dataFile."icons/default/index.theme".source = + "${defaultIndexThemePackage}/share/icons/default/index.theme"; + xdg.dataFile."icons/${cfg.name}".source = + "${cfg.package}/share/icons/${cfg.name}"; + } + + (mkIf cfg.dotIcons.enable { + # Add symlink of cursor icon directory to $HOME/.icons, needed for + # backwards compatibility with some applications. See: + # https://specifications.freedesktop.org/icon-theme-spec/latest/ar01s03.html + home.file.".icons/default/index.theme".source = + "${defaultIndexThemePackage}/share/icons/default/index.theme"; + home.file.".icons/${cfg.name}".source = + "${cfg.package}/share/icons/${cfg.name}"; + }) + + (mkIf cfg.x11.enable { + xsession.profileExtra = '' + ${pkgs.xorg.xsetroot}/bin/xsetroot -xcf ${cursorPath} ${ + toString cfg.size + } + ''; + + xresources.properties = { + "Xcursor.theme" = cfg.name; + "Xcursor.size" = cfg.size; + }; + }) + + (mkIf cfg.gtk.enable { + gtk.cursorTheme = mkDefault { inherit (cfg) package name size; }; + }) + + (mkIf cfg.hyprcursor.enable { + home.sessionVariables = { + HYPRCURSOR_THEME = cfg.name; + HYPRCURSOR_SIZE = if cfg.hyprcursor.size != null then + cfg.hyprcursor.size + else + cfg.size; + }; + }) + + (mkIf cfg.sway.enable { + wayland.windowManager.sway = { + config = { + seat = { + "*" = { + xcursor_theme = + "${cfg.name} ${toString config.gtk.cursorTheme.size}"; + }; + }; + }; + }; + }) + ])) + { - assertions = [ - (hm.assertions.assertPlatform "home.pointerCursor" pkgs platforms.linux) - ]; + warnings = (optional (any (x: + getAttrFromPath + ([ "xsession" "pointerCursor" ] ++ [ x ] ++ [ "isDefined" ]) + options) [ "package" "name" "size" "defaultCursor" ]) '' + The option `xsession.pointerCursor` has been merged into `home.pointerCursor` and will be removed + in the future. Please change to set `home.pointerCursor` directly and enable `home.pointerCursor.x11.enable` + to generate x11 specific cursor configurations. You can refer to the documentation for more details. + '') ++ (optional (opts.highestPrio != (lib.mkOptionDefault { }).priority + && cfg == null) '' + Setting home.pointerCursor to null is deprecated. + Please update your configuration to explicitly set: - home.packages = [ cfg.package defaultIndexThemePackage ]; - - # Set directory to look for cursors in, needed for some applications - # that are unable to find cursors otherwise. See: - # https://github.com/nix-community/home-manager/issues/2812 - # https://wiki.archlinux.org/title/Cursor_themes#Environment_variable - home.sessionVariables = { - XCURSOR_PATH = mkDefault ("$XCURSOR_PATH\${XCURSOR_PATH:+:}" - + "${config.home.profileDirectory}/share/icons"); - XCURSOR_SIZE = mkDefault cfg.size; - XCURSOR_THEME = mkDefault cfg.name; - }; - - # Add symlink of cursor icon directory to $HOME/.icons, needed for - # backwards compatibility with some applications. See: - # https://specifications.freedesktop.org/icon-theme-spec/latest/ar01s03.html - home.file.".icons/default/index.theme".source = - "${defaultIndexThemePackage}/share/icons/default/index.theme"; - home.file.".icons/${cfg.name}".source = - "${cfg.package}/share/icons/${cfg.name}"; - - # Add cursor icon link to $XDG_DATA_HOME/icons as well for redundancy. - xdg.dataFile."icons/default/index.theme".source = - "${defaultIndexThemePackage}/share/icons/default/index.theme"; - xdg.dataFile."icons/${cfg.name}".source = - "${cfg.package}/share/icons/${cfg.name}"; + home.pointerCursor.enable = false; + ''); } - - (mkIf cfg.x11.enable { - xsession.profileExtra = '' - ${pkgs.xorg.xsetroot}/bin/xsetroot -xcf ${cursorPath} ${ - toString cfg.size - } - ''; - - xresources.properties = { - "Xcursor.theme" = cfg.name; - "Xcursor.size" = cfg.size; - }; - }) - - (mkIf cfg.gtk.enable { - gtk.cursorTheme = mkDefault { inherit (cfg) package name size; }; - }) - - (mkIf cfg.hyprcursor.enable { - home.sessionVariables = { - HYPRCURSOR_THEME = cfg.name; - HYPRCURSOR_SIZE = - if cfg.hyprcursor.size != null then cfg.hyprcursor.size else cfg.size; - }; - }) - ]); + ]; } diff --git a/modules/config/i18n.nix b/modules/config/i18n.nix index 2efb53d62..409227236 100644 --- a/modules/config/i18n.nix +++ b/modules/config/i18n.nix @@ -17,8 +17,6 @@ { lib, pkgs, config, ... }: -with lib; - let inherit (config.i18n) glibcLocales; @@ -27,19 +25,19 @@ let archivePath = "${glibcLocales}/lib/locale/locale-archive"; # lookup the version of glibcLocales and set the appropriate environment vars - localeVars = if versionAtLeast version "2.27" then { + localeVars = if lib.versionAtLeast version "2.27" then { LOCALE_ARCHIVE_2_27 = archivePath; - } else if versionAtLeast version "2.11" then { + } else if lib.versionAtLeast version "2.11" then { LOCALE_ARCHIVE_2_11 = archivePath; } else { }; in { - meta.maintainers = with maintainers; [ midchildan ]; + meta.maintainers = with lib.maintainers; [ midchildan ]; options = { - i18n.glibcLocales = mkOption { - type = types.path; + i18n.glibcLocales = lib.mkOption { + type = lib.types.path; description = '' Customized `glibcLocales` package providing the `LOCALE_ARCHIVE_*` environment variable. @@ -50,7 +48,7 @@ in { will be set to {var}`i18n.glibcLocales` from the system configuration. ''; - example = literalExpression '' + example = lib.literalExpression '' pkgs.glibcLocales.override { allLocales = false; locales = [ "en_US.UTF-8/UTF-8" ]; @@ -58,11 +56,11 @@ in { ''; # NB. See nixos/default.nix for NixOS default. default = pkgs.glibcLocales; - defaultText = literalExpression "pkgs.glibcLocales"; + defaultText = lib.literalExpression "pkgs.glibcLocales"; }; }; - config = mkIf pkgs.stdenv.hostPlatform.isLinux { + config = lib.mkIf pkgs.stdenv.hostPlatform.isLinux { # For shell sessions. home.sessionVariables = localeVars; diff --git a/modules/default.nix b/modules/default.nix index 6c54148ab..05d2a504c 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -5,16 +5,14 @@ # Extra arguments passed to specialArgs. , extraSpecialArgs ? { } }: -with lib; - let collectFailed = cfg: - map (x: x.message) (filter (x: !x.assertion) cfg.assertions); + map (x: x.message) (lib.filter (x: !x.assertion) cfg.assertions); showWarnings = res: let f = w: x: builtins.trace "warning: ${w}" x; - in fold f res res.config.warnings; + in lib.fold f res res.config.warnings; extendedLib = import ./lib/stdlib-extended.nix lib; @@ -32,7 +30,7 @@ let moduleChecks = raw: showWarnings (let failed = collectFailed raw.config; - failedStr = concatStringsSep "\n" (map (x: "- ${x}") failed); + failedStr = lib.concatStringsSep "\n" (map (x: "- ${x}") failed); in if failed == [ ] then raw else @@ -52,8 +50,8 @@ let activation-script = module.config.home.activationPackage; newsDisplay = rawModule.config.news.display; - newsEntries = sort (a: b: a.time > b.time) - (filter (a: a.condition) rawModule.config.news.entries); + newsEntries = lib.sort (a: b: a.time > b.time) + (lib.filter (a: a.condition) rawModule.config.news.entries); inherit (module._module.args) pkgs; diff --git a/modules/files.nix b/modules/files.nix index 8c047bbeb..d359979db 100644 --- a/modules/files.nix +++ b/modules/files.nix @@ -1,10 +1,8 @@ { pkgs, config, lib, ... }: -with lib; - let - cfg = filterAttrs (n: f: f.enable) config.home.file; + cfg = lib.filterAttrs (n: f: f.enable) config.home.file; homeDirectory = config.home.homeDirectory; @@ -25,14 +23,14 @@ in { options = { - home.file = mkOption { + home.file = lib.mkOption { description = "Attribute set of files to link into the user home."; default = {}; type = fileType "home.file" "{env}`HOME`" homeDirectory; }; - home-files = mkOption { - type = types.package; + home-files = lib.mkOption { + type = lib.types.package; internal = true; description = "Package to contain all home files"; }; @@ -42,11 +40,11 @@ in assertions = [( let dups = - attrNames - (filterAttrs (n: v: v > 1) - (foldAttrs (acc: v: acc + v) 0 - (mapAttrsToList (n: v: { ${v.target} = 1; }) cfg))); - dupsStr = concatStringsSep ", " dups; + lib.attrNames + (lib.filterAttrs (n: v: v > 1) + (lib.foldAttrs (acc: v: acc + v) 0 + (lib.mapAttrsToList (n: v: { ${v.target} = 1; }) cfg))); + dupsStr = lib.concatStringsSep ", " dups; in { assertion = dups == []; message = '' @@ -64,22 +62,22 @@ in lib.file.mkOutOfStoreSymlink = path: let pathStr = toString path; - name = hm.strings.storeFileName (baseNameOf pathStr); + name = lib.hm.strings.storeFileName (baseNameOf pathStr); in - pkgs.runCommandLocal name {} ''ln -s ${escapeShellArg pathStr} $out''; + pkgs.runCommandLocal name {} ''ln -s ${lib.escapeShellArg pathStr} $out''; # This verifies that the links we are about to create will not # overwrite an existing file. - home.activation.checkLinkTargets = hm.dag.entryBefore ["writeBoundary"] ( + home.activation.checkLinkTargets = lib.hm.dag.entryBefore ["writeBoundary"] ( let # Paths that should be forcibly overwritten by Home Manager. # Caveat emptor! forcedPaths = - concatMapStringsSep " " (p: ''"$HOME"/${escapeShellArg p}'') - (mapAttrsToList (n: v: v.target) - (filterAttrs (n: v: v.force) cfg)); + lib.concatMapStringsSep " " (p: ''"$HOME"/${lib.escapeShellArg p}'') + (lib.mapAttrsToList (n: v: v.target) + (lib.filterAttrs (n: v: v.force) cfg)); - storeDir = escapeShellArg builtins.storeDir; + storeDir = lib.escapeShellArg builtins.storeDir; check = pkgs.substituteAll { src = ./files/check-link-targets.sh; @@ -118,7 +116,7 @@ in # and a failure during the intermediate state FA ∩ FB will not # result in lost links because this set of links are in both the # source and target generation. - home.activation.linkGeneration = hm.dag.entryAfter ["writeBoundary"] ( + home.activation.linkGeneration = lib.hm.dag.entryAfter ["writeBoundary"] ( let link = pkgs.writeShellScript "link" '' ${config.lib.bash.initHomeManagerLib} @@ -151,7 +149,7 @@ in # A symbolic link whose target path matches this pattern will be # considered part of a Home Manager generation. - homeFilePattern="$(readlink -e ${escapeShellArg builtins.storeDir})/*-home-manager-files/*" + homeFilePattern="$(readlink -e ${lib.escapeShellArg builtins.storeDir})/*-home-manager-files/*" newGenFiles="$1" shift 1 @@ -216,9 +214,9 @@ in '' ); - home.activation.checkFilesChanged = hm.dag.entryBefore ["linkGeneration"] ( + home.activation.checkFilesChanged = lib.hm.dag.entryBefore ["linkGeneration"] ( let - homeDirArg = escapeShellArg homeDirectory; + homeDirArg = lib.escapeShellArg homeDirectory; in '' function _cmp() { if [[ -d $1 && -d $2 ]]; then @@ -228,31 +226,31 @@ in fi } declare -A changedFiles - '' + concatMapStrings (v: + '' + lib.concatMapStrings (v: let - sourceArg = escapeShellArg (sourceStorePath v); - targetArg = escapeShellArg v.target; + sourceArg = lib.escapeShellArg (sourceStorePath v); + targetArg = lib.escapeShellArg v.target; in '' _cmp ${sourceArg} ${homeDirArg}/${targetArg} \ && changedFiles[${targetArg}]=0 \ || changedFiles[${targetArg}]=1 - '') (filter (v: v.onChange != "") (attrValues cfg)) + '') (lib.filter (v: v.onChange != "") (lib.attrValues cfg)) + '' unset -f _cmp '' ); - home.activation.onFilesChange = hm.dag.entryAfter ["linkGeneration"] ( - concatMapStrings (v: '' - if (( ''${changedFiles[${escapeShellArg v.target}]} == 1 )); then + home.activation.onFilesChange = lib.hm.dag.entryAfter ["linkGeneration"] ( + lib.concatMapStrings (v: '' + if (( ''${changedFiles[${lib.escapeShellArg v.target}]} == 1 )); then if [[ -v DRY_RUN || -v VERBOSE ]]; then - echo "Running onChange hook for" ${escapeShellArg v.target} + echo "Running onChange hook for" ${lib.escapeShellArg v.target} fi if [[ ! -v DRY_RUN ]]; then ${v.onChange} fi fi - '') (filter (v: v.onChange != "") (attrValues cfg)) + '') (lib.filter (v: v.onChange != "") (lib.attrValues cfg)) ); # Symlink directories and files that have the right execute bit. @@ -324,10 +322,10 @@ in fi fi } - '' + concatStrings ( - mapAttrsToList (n: v: '' + '' + lib.concatStrings ( + lib.mapAttrsToList (n: v: '' insertFile ${ - escapeShellArgs [ + lib.escapeShellArgs [ (sourceStorePath v) v.target (if v.executable == null diff --git a/modules/home-environment.nix b/modules/home-environment.nix index fffb3b1cf..9d792ca31 100644 --- a/modules/home-environment.nix +++ b/modules/home-environment.nix @@ -1,8 +1,7 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) literalExpression mkOption types; inherit (config.home) stateVersion; @@ -114,7 +113,7 @@ let layout = mkOption { type = with types; nullOr str; default = - if versionAtLeast config.home.stateVersion "19.09" + if lib.versionAtLeast config.home.stateVersion "19.09" then null else "us"; defaultText = literalExpression "null"; @@ -148,7 +147,7 @@ let variant = mkOption { type = with types; nullOr str; default = - if versionAtLeast config.home.stateVersion "19.09" + if lib.versionAtLeast config.home.stateVersion "19.09" then null else ""; defaultText = literalExpression "null"; @@ -167,10 +166,10 @@ let in { - meta.maintainers = [ maintainers.rycee ]; + meta.maintainers = [ lib.maintainers.rycee ]; imports = [ - (mkRemovedOptionModule [ "home" "sessionVariableSetter" ] '' + (lib.mkRemovedOptionModule [ "home" "sessionVariableSetter" ] '' Session variables are now always set through the shell. This is done automatically if the shell configuration is managed by Home Manager. If not, then you must source the @@ -223,7 +222,7 @@ in home.keyboard = mkOption { type = types.nullOr keyboardSubModule; - default = if versionAtLeast stateVersion "21.11" then null else { }; + default = if lib.versionAtLeast stateVersion "21.11" then null else { }; defaultText = literalExpression '' "{ }" for state version < 21.11, "null" for state version ≥ 21.11 @@ -310,7 +309,7 @@ in ".git/safe/../../bin" ]; description = '' - Extra directories to add to {env}`PATH`. + Extra directories to prepend to {env}`PATH`. These directories are added to the {env}`PATH` variable in a double-quoted context, so expressions like `$HOME` are @@ -320,6 +319,27 @@ in ''; }; + home.sessionSearchVariables = mkOption { + default = { }; + type = with types; attrsOf (listOf str); + example = { + MANPATH = [ + "$HOME/.npm-packages/man" + "\${xdg.configHome}/.local/share/man" + ]; + }; + description = '' + Extra directories to prepend to arbitrary PATH-like + environment variables (e.g.: {env}`MANPATH`). The values + will be concatenated by `:`. + These directories are added to the environment variable in a + double-quoted context, so expressions like `$HOME` are + expanded by the shell. However, since expressions like `~` or + `*` are escaped, they will end up in the environment + verbatim. + ''; + }; + home.sessionVariablesExtra = mkOption { type = types.lines; default = ""; @@ -355,7 +375,7 @@ in home.emptyActivationPath = mkOption { internal = true; type = types.bool; - default = versionAtLeast stateVersion "22.11"; + default = lib.versionAtLeast stateVersion "22.11"; defaultText = literalExpression '' false for state version < 22.11, true for state version ≥ 22.11 @@ -370,7 +390,7 @@ in }; home.activation = mkOption { - type = hm.types.dagOf types.str; + type = lib.hm.types.dagOf types.str; default = {}; example = literalExpression '' { @@ -475,7 +495,7 @@ in ''; }; - home.preferXdgDirectories = mkEnableOption "" // { + home.preferXdgDirectories = lib.mkEnableOption "" // { description = '' Whether to make programs use XDG directories whenever supported. ''; @@ -502,7 +522,7 @@ in config.home.enableNixpkgsReleaseCheck && hmRelease != nixpkgsRelease; in - optional releaseMismatch '' + lib.optional releaseMismatch '' You are using Home Manager version ${hmRelease} and @@ -520,11 +540,11 @@ in ''; home.username = - mkIf (versionOlder config.home.stateVersion "20.09") - (mkDefault (builtins.getEnv "USER")); + lib.mkIf (lib.versionOlder config.home.stateVersion "20.09") + (lib.mkDefault (builtins.getEnv "USER")); home.homeDirectory = - mkIf (versionOlder config.home.stateVersion "20.09") - (mkDefault (builtins.getEnv "HOME")); + lib.mkIf (lib.versionOlder config.home.stateVersion "20.09") + (lib.mkDefault (builtins.getEnv "HOME")); home.profileDirectory = if config.submoduleSupport.enable @@ -540,7 +560,7 @@ in home.sessionVariables = let - maybeSet = n: v: optionalAttrs (v != null) { ${n} = v; }; + maybeSet = n: v: lib.optionalAttrs (v != null) { ${n} = v; }; in (maybeSet "LANG" cfg.language.base) // @@ -576,17 +596,24 @@ in export __HM_SESS_VARS_SOURCED=1 ${config.lib.shell.exportAll cfg.sessionVariables} - '' + lib.optionalString (cfg.sessionPath != [ ]) '' - export PATH="$PATH''${PATH:+:}${concatStringsSep ":" cfg.sessionPath}" - '' + cfg.sessionVariablesExtra; + '' + lib.concatStringsSep "\n" + (lib.mapAttrsToList + (env: values: config.lib.shell.export + env + (config.lib.shell.prependToVar ":" env values)) + cfg.sessionSearchVariables) + "\n" + + cfg.sessionVariablesExtra; }; + home.sessionSearchVariables.PATH = + lib.mkIf (cfg.sessionPath != [ ]) cfg.sessionPath; + home.packages = [ config.home.sessionVariablesPackage ]; # The entry acting as a boundary between the activation script's "check" and # the "write" phases. This is where we commit to attempting to actually # activate the configuration. - home.activation.writeBoundary = hm.dag.entryAnywhere '' + home.activation.writeBoundary = lib.hm.dag.entryAnywhere '' if [[ ! -v oldGenPath || "$oldGenPath" != "$newGenPath" ]] ; then _i "Creating new profile generation" run nix-env $VERBOSE_ARG --profile "$genProfilePath" --set "$newGenPath" @@ -610,7 +637,7 @@ in # In case the user has moved from a user-install of Home Manager # to a submodule managed one we attempt to uninstall the # `home-manager-path` package if it is installed. - home.activation.installPackages = hm.dag.entryAfter ["writeBoundary"] ( + home.activation.installPackages = lib.hm.dag.entryAfter ["writeBoundary"] ( if config.submoduleSupport.externalPackageInstall then '' @@ -676,10 +703,10 @@ in _iNote "Activating %s" "${res.name}" ${res.data} ''; - sortedCommands = hm.dag.topoSort cfg.activation; + sortedCommands = lib.hm.dag.topoSort cfg.activation; activationCmds = if sortedCommands ? result then - concatStringsSep "\n" (map mkCmd sortedCommands.result) + lib.concatStringsSep "\n" (map mkCmd sortedCommands.result) else abort ("Dependency cycle in activation script: " + builtins.toJSON sortedCommands); @@ -708,7 +735,7 @@ in else ":$(${pkgs.coreutils}/bin/dirname $(${pkgs.coreutils}/bin/readlink -m $(type -p nix-env)))" ) - + optionalString (!cfg.emptyActivationPath) "\${PATH:+:}$PATH"; + + lib.optionalString (!cfg.emptyActivationPath) "\${PATH:+:}$PATH"; activationScript = pkgs.writeShellScript "activation-script" '' set -eu @@ -722,8 +749,8 @@ in ${builtins.readFile ./lib-bash/activation-init.sh} if [[ ! -v SKIP_SANITY_CHECKS ]]; then - checkUsername ${escapeShellArg config.home.username} - checkHomeDirectory ${escapeShellArg config.home.homeDirectory} + checkUsername ${lib.escapeShellArg config.home.username} + checkHomeDirectory ${lib.escapeShellArg config.home.homeDirectory} fi # Create a temporary GC root to prevent collection during activation. @@ -732,7 +759,7 @@ in ${activationCmds} - ${optionalString (!config.uninstall) '' + ${lib.optionalString (!config.uninstall) '' # Create the "current generation" GC root. run --silence nix-store --realise "$newGenPath" --add-root "$currentGenGcPath" diff --git a/modules/i18n/input-method/default.nix b/modules/i18n/input-method/default.nix index 5e3a89b33..d6a1beb8e 100644 --- a/modules/i18n/input-method/default.nix +++ b/modules/i18n/input-method/default.nix @@ -1,6 +1,5 @@ { config, pkgs, lib, ... }: -with lib; let cfg = config.i18n.inputMethod; @@ -26,9 +25,9 @@ in { options.i18n = { inputMethod = { - enabled = mkOption { - type = types.nullOr - (types.enum [ "fcitx" "fcitx5" "nabi" "uim" "hime" "kime" ]); + enabled = lib.mkOption { + type = lib.types.nullOr + (lib.types.enum [ "fcitx" "fcitx5" "nabi" "uim" "hime" "kime" ]); default = null; example = "fcitx5"; description = '' @@ -61,9 +60,9 @@ in { ''; }; - package = mkOption { + package = lib.mkOption { internal = true; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; default = null; description = '' The input method method package. @@ -72,9 +71,10 @@ in { }; }; - config = mkIf (cfg.enabled != null) { + config = lib.mkIf (cfg.enabled != null) { assertions = [ - (hm.assertions.assertPlatform "i18n.inputMethod" pkgs platforms.linux) + (lib.hm.assertions.assertPlatform "i18n.inputMethod" pkgs + lib.platforms.linux) { assertion = cfg.enabled != "fcitx"; message = "fcitx has been removed, please use fcitx5 instead"; @@ -84,5 +84,5 @@ in { home.packages = [ cfg.package gtk2Cache gtk3Cache ]; }; - meta.maintainers = with lib; [ hm.maintainers.kranzes ]; + meta.maintainers = [ lib.hm.maintainers.kranzes ]; } diff --git a/modules/i18n/input-method/fcitx5.nix b/modules/i18n/input-method/fcitx5.nix index 3e4e2f26d..be239b30f 100644 --- a/modules/i18n/input-method/fcitx5.nix +++ b/modules/i18n/input-method/fcitx5.nix @@ -1,7 +1,5 @@ { config, pkgs, lib, ... }: -with lib; - let im = config.i18n.inputMethod; cfg = im.fcitx5; @@ -9,25 +7,25 @@ let in { options = { i18n.inputMethod.fcitx5 = { - fcitx5-with-addons = mkOption { - type = types.package; + fcitx5-with-addons = lib.mkOption { + type = lib.types.package; default = pkgs.libsForQt5.fcitx5-with-addons; - example = literalExpression "pkgs.kdePackages.fcitx5-with-addons"; + example = lib.literalExpression "pkgs.kdePackages.fcitx5-with-addons"; description = '' The fcitx5 package to use. ''; }; - addons = mkOption { - type = with types; listOf package; + addons = lib.mkOption { + type = with lib.types; listOf package; default = [ ]; - example = literalExpression "with pkgs; [ fcitx5-rime ]"; + example = lib.literalExpression "with pkgs; [ fcitx5-rime ]"; description = '' Enabled Fcitx5 addons. ''; }; - waylandFrontend = mkOption { - type = types.bool; + waylandFrontend = lib.mkOption { + type = lib.types.bool; default = false; description = '' Use the Wayland input method frontend. @@ -37,23 +35,27 @@ in { }; }; - config = mkIf (im.enabled == "fcitx5") { + config = lib.mkIf (im.enabled == "fcitx5") { i18n.inputMethod.package = fcitx5Package; - home.sessionVariables = { - GLFW_IM_MODULE = "ibus"; # IME support in kitty - XMODIFIERS = "@im=fcitx"; - QT_PLUGIN_PATH = - "$QT_PLUGIN_PATH\${QT_PLUGIN_PATH:+:}${fcitx5Package}/${pkgs.qt6.qtbase.qtPluginPrefix}"; - } // lib.optionalAttrs (!cfg.waylandFrontend) { - GTK_IM_MODULE = "fcitx"; - QT_IM_MODULE = "fcitx"; + home = { + sessionVariables = { + GLFW_IM_MODULE = "ibus"; # IME support in kitty + XMODIFIERS = "@im=fcitx"; + } // lib.optionalAttrs (!cfg.waylandFrontend) { + GTK_IM_MODULE = "fcitx"; + QT_IM_MODULE = "fcitx"; + }; + + sessionSearchVariables.QT_PLUGIN_PATH = + [ "${fcitx5Package}/${pkgs.qt6.qtbase.qtPluginPrefix}" ]; }; systemd.user.services.fcitx5-daemon = { Unit = { Description = "Fcitx5 input method editor"; PartOf = [ "graphical-session.target" ]; + After = [ "graphical-session.target" ]; }; Service.ExecStart = "${fcitx5Package}/bin/fcitx5"; Install.WantedBy = [ "graphical-session.target" ]; diff --git a/modules/i18n/input-method/hime.nix b/modules/i18n/input-method/hime.nix index 7b5700a9d..2d6f4d500 100644 --- a/modules/i18n/input-method/hime.nix +++ b/modules/i18n/input-method/hime.nix @@ -1,7 +1,7 @@ { config, pkgs, lib, ... }: -with lib; { - config = mkIf (config.i18n.inputMethod.enabled == "hime") { +{ + config = lib.mkIf (config.i18n.inputMethod.enabled == "hime") { i18n.inputMethod.package = pkgs.hime; home.sessionVariables = { diff --git a/modules/i18n/input-method/nabi.nix b/modules/i18n/input-method/nabi.nix index 01f9f7911..a060f4800 100644 --- a/modules/i18n/input-method/nabi.nix +++ b/modules/i18n/input-method/nabi.nix @@ -1,7 +1,7 @@ { config, pkgs, lib, ... }: -with lib; { - config = mkIf (config.i18n.inputMethod.enabled == "nabi") { +{ + config = lib.mkIf (config.i18n.inputMethod.enabled == "nabi") { i18n.inputMethod.package = pkgs.nabi; home.sessionVariables = { diff --git a/modules/i18n/input-method/uim.nix b/modules/i18n/input-method/uim.nix index e7890352c..8dcfe3238 100644 --- a/modules/i18n/input-method/uim.nix +++ b/modules/i18n/input-method/uim.nix @@ -1,14 +1,13 @@ { config, pkgs, lib, ... }: -with lib; - let cfg = config.i18n.inputMethod.uim; in { options = { i18n.inputMethod.uim = { - toolbar = mkOption { - type = types.enum [ "gtk" "gtk3" "gtk-systray" "gtk3-systray" "qt4" ]; + toolbar = lib.mkOption { + type = + lib.types.enum [ "gtk" "gtk3" "gtk-systray" "gtk3-systray" "qt4" ]; default = "gtk"; example = "gtk-systray"; description = '' @@ -19,7 +18,7 @@ in { }; - config = mkIf (config.i18n.inputMethod.enabled == "uim") { + config = lib.mkIf (config.i18n.inputMethod.enabled == "uim") { i18n.inputMethod.package = pkgs.uim; home.sessionVariables = { diff --git a/modules/launchd/launchd.nix b/modules/launchd/launchd.nix index 9c9b54452..98024c584 100644 --- a/modules/launchd/launchd.nix +++ b/modules/launchd/launchd.nix @@ -25,9 +25,11 @@ { config, lib, ... }: -with lib; +let + inherit (lib) types mkOption; # added by Home Manager -{ + launchdTypes = import ./types.nix { inherit config lib; }; +in { freeformType = with types; attrsOf anything; # added by Home Manager options = { @@ -118,7 +120,7 @@ with lib; }; LimitLoadToSessionType = mkOption { - type = types.nullOr types.str; + type = types.nullOr (types.oneOf [ types.str (types.listOf types.str) ]); default = null; description = '' This configuration file only applies to sessions of the type specified. This key is used in concert @@ -369,60 +371,26 @@ with lib; StartCalendarInterval = mkOption { default = null; - example = { + example = [{ Hour = 2; Minute = 30; - }; + }]; description = '' - This optional key causes the job to be started every calendar interval as specified. Missing arguments - are considered to be wildcard. The semantics are much like `crontab(5)`. Unlike cron which skips job - invocations when the computer is asleep, launchd will start the job the next time the computer wakes + This optional key causes the job to be started every calendar interval as specified. The semantics are + much like {manpage}`crontab(5)`: Missing attributes are considered to be wildcard. Unlike cron which skips + job invocations when the computer is asleep, launchd will start the job the next time the computer wakes up. If multiple intervals transpire before the computer is woken, those events will be coalesced into - one event upon wake from sleep. + one event upon waking from sleep. + + ::: {.important} + The list must not be empty and must not contain duplicate entries (attrsets which compare equally). + ::: + + ::: {.caution} + Since missing attrs become wildcards, an empty attrset effectively means "every minute". + ::: ''; - type = types.nullOr (types.listOf (types.submodule { - options = { - Minute = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - The minute on which this job will be run. - ''; - }; - - Hour = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - The hour on which this job will be run. - ''; - }; - - Day = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - The day on which this job will be run. - ''; - }; - - Weekday = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - The weekday on which this job will be run (0 and 7 are Sunday). - ''; - }; - - Month = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - The month on which this job will be run. - ''; - }; - }; - })); + type = types.nullOr launchdTypes.StartCalendarInterval; }; StandardInPath = mkOption { @@ -669,22 +637,22 @@ with lib; resource limits based on what kind of job it is. If left unspecified, the system will apply light resource limits to the job, throttling its CPU usage and I/O bandwidth. The following are valid values: - Background - : Background jobs are generally processes that do work that was not directly requested by the user. - The resource limits applied to Background jobs are intended to prevent them from disrupting the - user experience. + Background + : Background jobs are generally processes that do work that was not directly requested by the user. + The resource limits applied to Background jobs are intended to prevent them from disrupting the + user experience. - Standard - : Standard jobs are equivalent to no ProcessType being set. + Standard + : Standard jobs are equivalent to no ProcessType being set. - Adaptive - : Adaptive jobs move between the Background and Interactive classifications based on activity over - XPC connections. See {manpage}`xpc_transaction_begin(3)` for details. + Adaptive + : Adaptive jobs move between the Background and Interactive classifications based on activity over + XPC connections. See `xpc_transaction_begin(3)` for details. - Interactive - : Interactive jobs run with the same resource limitations as apps, that is to say, none. Interactive - jobs are critical to maintaining a responsive user experience, and this key should only be - used if an app's ability to be responsive depends on it, and cannot be made Adaptive. + Interactive + : Interactive jobs run with the same resource limitations as apps, that is to say, none. Interactive + jobs are critical to maintaining a responsive user experience, and this key should only be + used if an app's ability to be responsive depends on it, and cannot be made Adaptive. ''; }; @@ -706,6 +674,15 @@ with lib; ''; }; + LowPriorityBackgroundIO = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + This optional key specifies whether the kernel should consider this daemon to be low priority when + doing file system I/O when the process is throttled with the Darwin-background classification. + ''; + }; + LaunchOnlyOnce = mkOption { type = types.nullOr types.bool; default = null; @@ -717,7 +694,7 @@ with lib; MachServices = mkOption { default = null; - example = { ResetAtClose = true; }; + example = { "org.nixos.service" = { ResetAtClose = true; }; }; description = '' This optional key is used to specify Mach services to be registered with the Mach bootstrap sub-system. Each key in this dictionary should be the name of service to be advertised. The value of the key must @@ -726,31 +703,32 @@ with lib; Finally, for the job itself, the values will be replaced with Mach ports at the time of check-in with launchd. ''; - type = types.nullOr (types.submodule { - options = { - ResetAtClose = mkOption { - type = types.nullOr types.bool; - default = null; - description = '' - If this boolean is false, the port is recycled, thus leaving clients to remain oblivious to the - demand nature of job. If the value is set to true, clients receive port death notifications when - the job lets go of the receive right. The port will be recreated atomically with respect to bootstrap_look_up() - calls, so that clients can trust that after receiving a port death notification, - the new port will have already been recreated. Setting the value to true should be done with - care. Not all clients may be able to handle this behavior. The default value is false. - ''; - }; + type = types.nullOr (types.attrsOf (types.either types.bool + (types.submodule { + options = { + ResetAtClose = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + If this boolean is false, the port is recycled, thus leaving clients to remain oblivious to the + demand nature of job. If the value is set to true, clients receive port death notifications when + the job lets go of the receive right. The port will be recreated atomically with respect to bootstrap_look_up() + calls, so that clients can trust that after receiving a port death notification, + the new port will have already been recreated. Setting the value to true should be done with + care. Not all clients may be able to handle this behavior. The default value is false. + ''; + }; - HideUntilCheckIn = mkOption { - type = types.nullOr types.bool; - default = null; - description = '' - Reserve the name in the namespace, but cause bootstrap_look_up() to fail until the job has - checked in with launchd. - ''; + HideUntilCheckIn = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Reserve the name in the namespace, but cause bootstrap_look_up() to fail until the job has + checked in with launchd. + ''; + }; }; - }; - }); + }))); }; LaunchEvents = mkOption { @@ -778,6 +756,26 @@ with lib; }; }; + ServiceIPC = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + This optional key specifies whether the job participates in advanced + communication with launchd. The default is false. This flag is + incompatible with the inetdCompatibility key. + ''; + }; + + SessionCreate = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + This key specifies that the job should be spawned into a new security + audit session rather than the default session for the context is belongs + to. See auditon(2) for details. + ''; + }; + Sockets = mkOption { default = null; description = '' diff --git a/modules/launchd/types.nix b/modules/launchd/types.nix new file mode 100644 index 000000000..fadf46cb5 --- /dev/null +++ b/modules/launchd/types.nix @@ -0,0 +1,121 @@ +# launchd option type from nix-darwin +# +# Original code from https://github.com/LnL7/nix-darwin/commit/861af0fc94df9454f4e92d6892f75588763164bb + +{ lib, ... }: + +let + inherit (lib) imap1 types mkOption showOption mergeDefinitions; + inherit (builtins) map filter length deepSeq throw toString concatLists; + inherit (lib.options) showDefs; + wildcardText = lib.literalMD "`*`"; + + /* * + A type of list which does not allow duplicate elements. The base/inner + list type to use (e.g. `types.listOf` or `types.nonEmptyListOf`) is passed + via argument `listType`, which must be the final type and not a function. + + NOTE: The extra check for duplicates is quadratic and strict, so use this + type sparingly and only: + + * when needed, and + * when the list is expected to be recursively short (e.g. < 10 elements) + and shallow (i.e. strict evaluation of the list won't take too long) + + The implementation of this function is similar to that of + `types.nonEmptyListOf`. + */ + types'.uniqueList = listType: + listType // { + description = "unique ${ + types.optionDescriptionPhrase (class: class == "noun") listType + }"; + substSubModules = m: types'.uniqueList (listType.substSubModules m); + # This has been taken from the implementation of `types.listOf`, but has + # been modified to throw on duplicates. This check cannot be done in the + # `check` fn as this check is deep/strict, and because `check` runs + # prior to merging. + merge = loc: defs: + let + # Each element of `dupes` is a list. When there are duplicates, + # later lists will be duplicates of earlier lists, so just throw on + # the first set of duplicates found so that we don't have duplicate + # error msgs. + checked = filter (li: + if length li > 1 then + throw '' + The option `${ + showOption loc + }' contains duplicate entries after merging: + ${showDefs li}'' + else + false) dupes; + dupes = + map (def: filter (def': def'.value == def.value) merged) merged; + merged = filter (x: x ? value) (concatLists (imap1 (n: def: + imap1 (m: el: + let + inherit (def) file; + loc' = loc + ++ [ "[definition ${toString n}-entry ${toString m}]" ]; + in (mergeDefinitions loc' listType.nestedTypes.elemType [{ + inherit file; + value = el; + }]).optionalValue // { + inherit loc' file; + }) def.value) defs)); + in deepSeq checked (map (x: x.value) merged); + }; +in { + StartCalendarInterval = let + CalendarIntervalEntry = types.submodule { + options = { + Minute = mkOption { + type = types.nullOr (types.ints.between 0 59); + default = null; + defaultText = wildcardText; + description = '' + The minute on which this job will be run. + ''; + }; + + Hour = mkOption { + type = types.nullOr (types.ints.between 0 23); + default = null; + defaultText = wildcardText; + description = '' + The hour on which this job will be run. + ''; + }; + + Day = mkOption { + type = types.nullOr (types.ints.between 1 31); + default = null; + defaultText = wildcardText; + description = '' + The day on which this job will be run. + ''; + }; + + Weekday = mkOption { + type = types.nullOr (types.ints.between 0 7); + default = null; + defaultText = wildcardText; + description = '' + The weekday on which this job will be run (0 and 7 are Sunday). + ''; + }; + + Month = mkOption { + type = types.nullOr (types.ints.between 1 12); + default = null; + defaultText = wildcardText; + description = '' + The month on which this job will be run. + ''; + }; + }; + }; + in types.either CalendarIntervalEntry + (types'.uniqueList (types.nonEmptyListOf CalendarIntervalEntry)); +} diff --git a/modules/lib/maintainers.nix b/modules/lib/maintainers.nix index 52da8f0b0..9fb20cdd5 100644 --- a/modules/lib/maintainers.nix +++ b/modules/lib/maintainers.nix @@ -24,6 +24,12 @@ github = "afresquet"; githubId = 29437693; }; + aguirre-matteo = { + name = "aguirre-matteo"; + email = "aguirre.matteo.nix@gmail.com"; + github = "aguirre-matteo"; + githubId = 158215792; + }; amesgen = { name = "amesgen"; email = "amesgen@amesgen.de"; @@ -60,6 +66,12 @@ github = "bertof"; githubId = 9915675; }; + bmrips = { + name = "Benedikt Rips"; + email = "benedikt.rips@gmail.com"; + github = "bmrips"; + githubId = 20407973; + }; bricked = { name = "Bricked"; email = "hello@bricked.dev"; @@ -112,6 +124,12 @@ github = "diniamo"; githubId = 55629891; }; + dsoverlord = { + name = "Kirill Zakharov"; + email = "dsoverlord@vk.com"; + github = "dsoverlord"; + githubId = 78819443; + }; dwagenk = { email = "dwagenk@mailbox.org"; github = "dwagenk"; @@ -124,6 +142,14 @@ githubId = "56848082"; name = "Henri Sota"; }; + hey2022 = { + name = "Yiheng He"; + email = "yiheng.he@proton.me"; + matrix = "@hey2022:matrix.org"; + github = "hey2022"; + keys = + [{ fingerprint = "128E 09C0 6F73 D678 6BB5 E551 5EA5 3C75 F7BE 3EDE"; }]; + }; jack5079 = { name = "Jack W."; email = "nix@jack.cab"; @@ -137,6 +163,15 @@ github = "Janik-Haag"; githubId = 80165193; }; + jess = { + name = "Jessica"; + email = "jess+nix@jessie.cafe"; + githubId = 43591752; + keys = [{ + longkeyid = "rsa3072/0xBA3350686C918606"; + fingerprint = "8092 3BD1 ECD0 E436 671D C8E9 BA33 5068 6C91 8606"; + }]; + }; jkarlson = { email = "jekarlson@gmail.com"; github = "jkarlson"; @@ -275,6 +310,12 @@ github = "mifom"; githubId = 23462908; }; + msyds = { + name = "Madeleine Sydney Ślaga"; + email = "65362461+msyds@users.noreply.github.com"; + github = "msyds"; + githubId = 65362461; + }; nikp123 = { name = "nikp123"; email = "nikp123@users.noreply.github.com"; @@ -667,4 +708,28 @@ fingerprint = "AD32 73D4 5E0E 9478 E826 543F EDB2 C634 166A E6AD"; }]; }; + folliehiyuki = { + name = "Hoang Nguyen"; + email = "folliekazetani@protonmail.com"; + github = "folliehiyuki"; + githubId = 67634026; + }; + "3ulalia" = { + name = "Eulalia del Sol"; + email = "3ulalia@proton.me"; + github = "3ulalia"; + githubId = "179992797"; + }; + ipsavitsky = { + name = "Ilya Savitsky"; + email = "ipsavitsky234@gmail.com"; + github = "ipsavitsky"; + githubId = 33558632; + }; + noodlez = { + name = "Nathaniel Barragan"; + email = "contact@nathanielbarragan.xyz"; + github = "Noodlez1232"; + githubId = 12480453; + }; } diff --git a/modules/lib/shell.nix b/modules/lib/shell.nix index ae30e0b0f..04f9135cf 100644 --- a/modules/lib/shell.nix +++ b/modules/lib/shell.nix @@ -17,6 +17,14 @@ let }; in rec { + # Produces a Bourne shell like statement that prepend new values to + # an possibly existing variable, using sep(arator). + # Example: + # prependToVar ":" "PATH" [ "$HOME/bin" "$HOME/.local/bin" ] + # => "$HOME/bin:$HOME/.local/bin:${PATH:+:}\$PATH" + prependToVar = sep: n: v: + "${lib.concatStringsSep sep v}\${${n}:+${sep}}\$${n}"; + # Produces a Bourne shell like variable export statement. export = n: v: ''export ${n}="${toString v}"''; diff --git a/modules/manual.nix b/modules/manual.nix index 23963c3c0..02a5c2c77 100644 --- a/modules/manual.nix +++ b/modules/manual.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.manual; @@ -13,8 +11,8 @@ let in { options = { - manual.html.enable = mkOption { - type = types.bool; + manual.html.enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to install the HTML manual. This also installs the @@ -23,8 +21,8 @@ in { ''; }; - manual.manpages.enable = mkOption { - type = types.bool; + manual.manpages.enable = lib.mkOption { + type = lib.types.bool; default = true; example = false; description = '' @@ -37,8 +35,8 @@ in { ''; }; - manual.json.enable = mkOption { - type = types.bool; + manual.json.enable = lib.mkOption { + type = lib.types.bool; default = false; example = true; description = '' @@ -52,10 +50,10 @@ in { }; config = { - home.packages = mkMerge [ - (mkIf cfg.html.enable [ docs.manual.html docs.manual.htmlOpenTool ]) - (mkIf cfg.manpages.enable [ docs.manPages ]) - (mkIf cfg.json.enable [ docs.options.json ]) + home.packages = lib.mkMerge [ + (lib.mkIf cfg.html.enable [ docs.manual.html docs.manual.htmlOpenTool ]) + (lib.mkIf cfg.manpages.enable [ docs.manPages ]) + (lib.mkIf cfg.json.enable [ docs.options.json ]) ]; }; diff --git a/modules/misc/dconf.nix b/modules/misc/dconf.nix index b4863a139..39eceb42e 100644 --- a/modules/misc/dconf.nix +++ b/modules/misc/dconf.nix @@ -1,29 +1,29 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) types; cfg = config.dconf; - toDconfIni = generators.toINI { mkKeyValue = mkIniKeyValue; }; + toDconfIni = lib.generators.toINI { mkKeyValue = mkIniKeyValue; }; - mkIniKeyValue = key: value: "${key}=${toString (hm.gvariant.mkValue value)}"; + mkIniKeyValue = key: value: + "${key}=${toString (lib.hm.gvariant.mkValue value)}"; # The dconf keys managed by this configuration. We store this as part of the # generation state to be able to reset keys that become unmanaged during # switch. stateDconfKeys = pkgs.writeText "dconf-keys.json" (builtins.toJSON - (concatLists (mapAttrsToList - (dir: entries: mapAttrsToList (key: _: "/${dir}/${key}") entries) + (lib.concatLists (lib.mapAttrsToList + (dir: entries: lib.mapAttrsToList (key: _: "/${dir}/${key}") entries) cfg.settings))); in { - meta.maintainers = [ maintainers.rycee ]; + meta.maintainers = [ lib.maintainers.rycee ]; options = { dconf = { - enable = mkOption { + enable = lib.mkOption { type = types.bool; # While technically dconf on darwin could work, our activation step # requires dbus, which only *lightly* supports Darwin in general, and @@ -43,10 +43,10 @@ in { ''; }; - settings = mkOption { - type = with types; attrsOf (attrsOf hm.types.gvariant); + settings = lib.mkOption { + type = with types; attrsOf (attrsOf lib.hm.types.gvariant); default = { }; - example = literalExpression '' + example = lib.literalExpression '' { "org/gnome/calculator" = { button-mode = "programming"; @@ -75,7 +75,7 @@ in { }; }; - config = mkIf (cfg.enable && cfg.settings != { }) { + config = lib.mkIf (cfg.enable && cfg.settings != { }) { # Make sure the dconf directory exists. xdg.configFile."dconf/.keep".source = builtins.toFile "keep" ""; @@ -84,53 +84,54 @@ in { ln -s ${stateDconfKeys} $out/state/${stateDconfKeys.name} ''; - home.activation.dconfSettings = hm.dag.entryAfter [ "installPackages" ] (let - iniFile = pkgs.writeText "hm-dconf.ini" (toDconfIni cfg.settings); + home.activation.dconfSettings = lib.hm.dag.entryAfter [ "installPackages" ] + (let + iniFile = pkgs.writeText "hm-dconf.ini" (toDconfIni cfg.settings); - statePath = "state/${stateDconfKeys.name}"; + statePath = "state/${stateDconfKeys.name}"; - cleanup = pkgs.writeShellScript "dconf-cleanup" '' - set -euo pipefail + cleanup = pkgs.writeShellScript "dconf-cleanup" '' + set -euo pipefail - ${config.lib.bash.initHomeManagerLib} + ${config.lib.bash.initHomeManagerLib} - PATH=${makeBinPath [ pkgs.dconf pkgs.jq ]}''${PATH:+:}$PATH + PATH=${lib.makeBinPath [ pkgs.dconf pkgs.jq ]}''${PATH:+:}$PATH - oldState="$1" - newState="$2" + oldState="$1" + newState="$2" - # Can't do cleanup if we don't know the old state. - if [[ ! -f $oldState ]]; then - exit 0 + # Can't do cleanup if we don't know the old state. + if [[ ! -f $oldState ]]; then + exit 0 + fi + + # Reset all keys that are present in the old generation but not the new + # one. + jq -r -n \ + --slurpfile old "$oldState" \ + --slurpfile new "$newState" \ + '($old[] - $new[])[]' \ + | while read -r key; do + verboseEcho "Resetting dconf key \"$key\"" + run $DCONF_DBUS_RUN_SESSION dconf reset "$key" + done + ''; + in '' + if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then + export DCONF_DBUS_RUN_SESSION="" + else + export DCONF_DBUS_RUN_SESSION="${pkgs.dbus}/bin/dbus-run-session --dbus-daemon=${pkgs.dbus}/bin/dbus-daemon" fi - # Reset all keys that are present in the old generation but not the new - # one. - jq -r -n \ - --slurpfile old "$oldState" \ - --slurpfile new "$newState" \ - '($old[] - $new[])[]' \ - | while read -r key; do - verboseEcho "Resetting dconf key \"$key\"" - run $DCONF_DBUS_RUN_SESSION dconf reset "$key" - done - ''; - in '' - if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then - export DCONF_DBUS_RUN_SESSION="" - else - export DCONF_DBUS_RUN_SESSION="${pkgs.dbus}/bin/dbus-run-session --dbus-daemon=${pkgs.dbus}/bin/dbus-daemon" - fi + if [[ -v oldGenPath ]]; then + ${cleanup} \ + "$oldGenPath/${statePath}" \ + "$newGenPath/${statePath}" + fi - if [[ -v oldGenPath ]]; then - ${cleanup} \ - "$oldGenPath/${statePath}" \ - "$newGenPath/${statePath}" - fi + run $DCONF_DBUS_RUN_SESSION ${pkgs.dconf}/bin/dconf load / < ${iniFile} - run $DCONF_DBUS_RUN_SESSION ${pkgs.dconf}/bin/dconf load / < ${iniFile} - - unset DCONF_DBUS_RUN_SESSION - ''); + unset DCONF_DBUS_RUN_SESSION + ''); }; } diff --git a/modules/misc/debug.nix b/modules/misc/debug.nix index fc0d8946a..eb9d85655 100644 --- a/modules/misc/debug.nix +++ b/modules/misc/debug.nix @@ -1,10 +1,8 @@ -{ config, pkgs, lib, ... }: - -with lib; +{ config, lib, ... }: { options.home = { - enableDebugInfo = mkEnableOption "" // { + enableDebugInfo = lib.mkEnableOption "" // { description = '' Some Nix packages provide debug symbols for {command}`gdb` in the `debug` output. @@ -15,12 +13,11 @@ with lib; }; }; - config = mkIf config.home.enableDebugInfo { + config = lib.mkIf config.home.enableDebugInfo { home.extraOutputsToInstall = [ "debug" ]; - home.sessionVariables = { - NIX_DEBUG_INFO_DIRS = - "$NIX_DEBUG_INFO_DIRS\${NIX_DEBUG_INFO_DIRS:+:}${config.home.profileDirectory}/lib/debug"; + home.sessionSearchVariables = { + NIX_DEBUG_INFO_DIRS = [ "${config.home.profileDirectory}/lib/debug" ]; }; }; } diff --git a/modules/misc/editorconfig.nix b/modules/misc/editorconfig.nix index a6dfb570a..56505850a 100644 --- a/modules/misc/editorconfig.nix +++ b/modules/misc/editorconfig.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.editorconfig; @@ -9,12 +7,12 @@ let iniFormat = pkgs.formats.ini { }; in { - meta.maintainers = with maintainers; [ loicreynier ]; + meta.maintainers = with lib.maintainers; [ loicreynier ]; options.editorconfig = { - enable = mkEnableOption "EditorConfig home configuration file"; + enable = lib.mkEnableOption "EditorConfig home configuration file"; - settings = mkOption { + settings = lib.mkOption { type = iniFormat.type; default = { }; description = '' @@ -23,7 +21,7 @@ in { it must not be added here. See for documentation. ''; - example = literalExpression '' + example = lib.literalExpression '' { "*" = { charset = "utf-8"; @@ -39,9 +37,9 @@ in { }; }; - config = mkIf (cfg.enable && cfg.settings != { }) { + config = lib.mkIf (cfg.enable && cfg.settings != { }) { home.file.".editorconfig".text = let - renderedSettings = generators.toINIWithGlobalSection { } { + renderedSettings = lib.generators.toINIWithGlobalSection { } { globalSection = { root = true; }; sections = cfg.settings; }; diff --git a/modules/misc/fontconfig.nix b/modules/misc/fontconfig.nix index 9bc6ac47b..09906a440 100644 --- a/modules/misc/fontconfig.nix +++ b/modules/misc/fontconfig.nix @@ -4,8 +4,6 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.fonts.fontconfig; @@ -13,10 +11,10 @@ let profileDirectory = config.home.profileDirectory; in { - meta.maintainers = [ maintainers.rycee ]; + meta.maintainers = [ lib.maintainers.rycee ]; imports = [ - (mkRenamedOptionModule [ "fonts" "fontconfig" "enableProfileFonts" ] [ + (lib.mkRenamedOptionModule [ "fonts" "fontconfig" "enableProfileFonts" ] [ "fonts" "fontconfig" "enable" @@ -25,8 +23,8 @@ in { options = { fonts.fontconfig = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable fontconfig configuration. This will, for @@ -38,8 +36,8 @@ in { }; defaultFonts = { - monospace = mkOption { - type = with types; listOf str; + monospace = lib.mkOption { + type = with lib.types; listOf str; default = [ ]; description = '' Per-user default monospace font(s). Multiple fonts may be listed in @@ -47,8 +45,8 @@ in { ''; }; - sansSerif = mkOption { - type = with types; listOf str; + sansSerif = lib.mkOption { + type = with lib.types; listOf str; default = [ ]; description = '' Per-user default sans serif font(s). Multiple fonts may be listed @@ -56,8 +54,8 @@ in { ''; }; - serif = mkOption { - type = with types; listOf str; + serif = lib.mkOption { + type = with lib.types; listOf str; default = [ ]; description = '' Per-user default serif font(s). Multiple fonts may be listed in @@ -65,8 +63,8 @@ in { ''; }; - emoji = mkOption { - type = with types; listOf str; + emoji = lib.mkOption { + type = with lib.types; listOf str; default = [ ]; description = '' Per-user default emoji font(s). Multiple fonts may be listed in @@ -83,7 +81,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.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. @@ -105,7 +103,7 @@ in { EOF - ${getBin pkgs.fontconfig}/bin/fc-cache -f + ${lib.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 @@ -147,12 +145,12 @@ in { "fontconfig/conf.d/52-hm-default-fonts.conf".text = let genDefault = fonts: name: - optionalString (fonts != [ ]) '' + lib.optionalString (fonts != [ ]) '' ${name} ${ - concatStringsSep "" (map (font: '' + lib.concatStringsSep "" (map (font: '' ${font} '') fonts) } diff --git a/modules/misc/gtk.nix b/modules/misc/gtk.nix index 65ed1de2f..f6ee95a19 100644 --- a/modules/misc/gtk.nix +++ b/modules/misc/gtk.nix @@ -1,29 +1,30 @@ -{ config, lib, pkgs, ... }: - -with lib; +{ config, lib, ... }: let + inherit (lib) literalExpression mkOption optionalAttrs types; cfg = config.gtk; cfg2 = config.gtk.gtk2; cfg3 = config.gtk.gtk3; cfg4 = config.gtk.gtk4; - toGtk3Ini = generators.toINI { + toGtk3Ini = lib.generators.toINI { mkKeyValue = key: value: - let value' = if isBool value then boolToString value else toString value; - in "${escape [ "=" ] key}=${value'}"; + let + value' = + if lib.isBool value then lib.boolToString value else toString value; + in "${lib.escape [ "=" ] key}=${value'}"; }; formatGtk2Option = n: v: let - v' = if isBool v then - boolToString value - else if isString v then + v' = if lib.isBool v then + lib.boolToString lib.value + else if lib.isString v then ''"${v}"'' else toString v; - in "${escape [ "=" ] n} = ${v'}"; + in "${lib.escape [ "=" ] n} = ${v'}"; themeType = types.submodule { options = { @@ -100,20 +101,20 @@ let }; in { - meta.maintainers = [ maintainers.rycee ]; + meta.maintainers = [ lib.maintainers.rycee ]; imports = [ - (mkRemovedOptionModule [ "gtk" "gtk3" "waylandSupport" ] '' + (lib.mkRemovedOptionModule [ "gtk" "gtk3" "waylandSupport" ] '' This options is not longer needed and can be removed. '') ]; options = { gtk = { - enable = mkEnableOption "GTK 2/3 configuration"; + enable = lib.mkEnableOption "GTK 2/3 configuration"; font = mkOption { - type = types.nullOr hm.types.fontType; + type = types.nullOr lib.hm.types.fontType; default = null; description = '' The font to use in GTK+ 2/3 applications. @@ -219,7 +220,7 @@ in { }; }; - config = mkIf cfg.enable (let + config = lib.mkIf cfg.enable (let gtkIni = optionalAttrs (cfg.font != null) { gtk-font-name = let fontSize = if cfg.font.size != null then cfg.font.size else 10; @@ -258,18 +259,17 @@ in { }; optionalPackage = opt: - optional (opt != null && opt.package != null) opt.package; + lib.optional (opt != null && opt.package != null) opt.package; in { - home.packages = concatMap optionalPackage [ + home.packages = lib.concatMap optionalPackage [ cfg.font cfg.theme cfg.iconTheme cfg.cursorTheme ]; - home.file.${cfg2.configLocation}.text = - concatMapStrings (l: l + "\n") (mapAttrsToList formatGtk2Option gtkIni) - + cfg2.extraConfig + "\n"; + home.file.${cfg2.configLocation}.text = lib.concatMapStrings (l: l + "\n") + (lib.mapAttrsToList formatGtk2Option gtkIni) + cfg2.extraConfig + "\n"; home.sessionVariables.GTK2_RC_FILES = cfg2.configLocation; @@ -277,16 +277,17 @@ in { toGtk3Ini { Settings = gtkIni // cfg3.extraConfig; }; xdg.configFile."gtk-3.0/gtk.css" = - mkIf (cfg3.extraCss != "") { text = cfg3.extraCss; }; + lib.mkIf (cfg3.extraCss != "") { text = cfg3.extraCss; }; - xdg.configFile."gtk-3.0/bookmarks" = mkIf (cfg3.bookmarks != [ ]) { - text = concatMapStrings (l: l + "\n") cfg3.bookmarks; + xdg.configFile."gtk-3.0/bookmarks" = lib.mkIf (cfg3.bookmarks != [ ]) { + text = lib.concatMapStrings (l: l + "\n") cfg3.bookmarks; }; xdg.configFile."gtk-4.0/settings.ini".text = toGtk3Ini { Settings = gtkIni // cfg4.extraConfig; }; - xdg.configFile."gtk-4.0/gtk.css" = mkIf (gtk4Css != "") { text = gtk4Css; }; + xdg.configFile."gtk-4.0/gtk.css" = + lib.mkIf (gtk4Css != "") { text = gtk4Css; }; dconf.settings."org/gnome/desktop/interface" = dconfIni; }); diff --git a/modules/misc/mozilla-messaging-hosts.nix b/modules/misc/mozilla-messaging-hosts.nix new file mode 100644 index 000000000..09a4188f1 --- /dev/null +++ b/modules/misc/mozilla-messaging-hosts.nix @@ -0,0 +1,92 @@ +{ config, lib, pkgs, ... }: + +let + inherit (pkgs.stdenv) isDarwin; + + cfg = config.mozilla; + + defaultPaths = [ + # Link a .keep file to keep the directory around + (pkgs.writeTextDir "lib/mozilla/native-messaging-hosts/.keep" "") + ]; + + thunderbirdNativeMessagingHostsPath = if isDarwin then + "Library/Mozilla/NativeMessagingHosts" + else + ".mozilla/native-messaging-hosts"; + + firefoxNativeMessagingHostsPath = if isDarwin then + "Library/Application Support/Mozilla/NativeMessagingHosts" + else + ".mozilla/native-messaging-hosts"; +in { + meta.maintainers = with lib.maintainers; [ + booxter + rycee + lib.hm.maintainers.bricked + ]; + + options.mozilla = { + firefoxNativeMessagingHosts = lib.mkOption { + internal = true; + type = with lib.types; listOf package; + default = [ ]; + description = '' + List of Firefox native messaging hosts to configure. + ''; + }; + + thunderbirdNativeMessagingHosts = lib.mkOption { + internal = true; + type = with lib.types; listOf package; + default = [ ]; + description = '' + List of Thunderbird native messaging hosts to configure. + ''; + }; + }; + + config = lib.mkIf (cfg.firefoxNativeMessagingHosts != [ ] + || cfg.thunderbirdNativeMessagingHosts != [ ]) { + home.file = if isDarwin then + let + firefoxNativeMessagingHostsJoined = pkgs.symlinkJoin { + name = "ff-native-messaging-hosts"; + paths = defaultPaths ++ cfg.firefoxNativeMessagingHosts; + }; + thunderbirdNativeMessagingHostsJoined = pkgs.symlinkJoin { + name = "th-native-messaging-hosts"; + paths = defaultPaths ++ cfg.thunderbirdNativeMessagingHosts; + }; + in { + "${thunderbirdNativeMessagingHostsPath}" = + lib.mkIf (cfg.thunderbirdNativeMessagingHosts != [ ]) { + source = + "${thunderbirdNativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts"; + recursive = true; + }; + + "${firefoxNativeMessagingHostsPath}" = + lib.mkIf (cfg.firefoxNativeMessagingHosts != [ ]) { + source = + "${firefoxNativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts"; + recursive = true; + }; + } + else + let + nativeMessagingHostsJoined = pkgs.symlinkJoin { + name = "mozilla-native-messaging-hosts"; + # on Linux, the directory is shared between Firefox and Thunderbird; merge both into one + paths = defaultPaths ++ cfg.firefoxNativeMessagingHosts + ++ cfg.thunderbirdNativeMessagingHosts; + }; + in { + "${firefoxNativeMessagingHostsPath}" = { + source = + "${nativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts"; + recursive = true; + }; + }; + }; +} diff --git a/modules/misc/news.nix b/modules/misc/news.nix index 395a45d5f..51c35976a 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -1,6 +1,8 @@ -{ config, lib, options, pkgs, ... }: -with lib; +{ config, lib, pkgs, ... }: + let + inherit (lib) mkOption types; + cfg = config.news; hostPlatform = pkgs.stdenv.hostPlatform; @@ -39,10 +41,12 @@ let }; }; - config = { id = mkDefault (builtins.hashString "sha256" config.message); }; + config = { + id = lib.mkDefault (builtins.hashString "sha256" config.message); + }; }); in { - meta.maintainers = [ maintainers.rycee ]; + meta.maintainers = [ lib.maintainers.rycee ]; options = { news = { @@ -1891,8 +1895,8 @@ in { { time = "2024-12-08T17:22:13+00:00"; condition = let - usingMbsync = any (a: a.mbsync.enable) - (attrValues config.accounts.email.accounts); + usingMbsync = lib.any (a: a.mbsync.enable) + (lib.attrValues config.accounts.email.accounts); in usingMbsync; message = '' isync/mbsync 1.5.0 has changed several things. @@ -2062,6 +2066,120 @@ in { See https://github.com/mateusauler/git-worktree-switcher for more. ''; } + + { + time = "2025-02-20T18:39:31+00:00"; + condition = hostPlatform.isLinux; + message = '' + A new module is available: 'programs.swayimg'. + + swayimg is a fully customizable and lightweight image viewer for + Wayland based display servers. + See https://github.com/artemsen/swayimg for more. + ''; + } + + { + time = "2025-02-16T17:00:00+00:00"; + message = '' + A new module is available: 'services.wluma'. + + Wluma is a tool for Wayland compositors to automatically adjust + screen brightness based on the screen contents and amount of ambient light around you. + ''; + } + + { + time = "2025-02-21T16:53:20+00:00"; + message = '' + A new module is available: 'programs.earthly'. + + Earthly is a build configuration framework utilizing buildkit and + Dockerfile-like syntax for fast builds and simplicity. + ''; + } + + { + time = "2025-02-22T16:53:20+00:00"; + message = '' + A new module is available: 'programs.jqp'. + + A TUI playground for experimenting with `jq`. + ''; + } + + { + time = "2025-02-22T16:46:56+00:00"; + condition = hostPlatform.isLinux; + message = '' + A new module is available: 'services.wpaperd'. + + This replaces the existing module, 'programs.wpaperd', and adds a + systemd service to ensure its execution. + ''; + } + + { + time = "2025-01-26T16:40:00+00:00"; + message = '' + A new module is available: 'programs.mods' + + mods is a command line AI tool that is highly configurable and allows + querying AI models hosted locally or by other services (OpenAI, + Cohere, Groq). + ''; + } + + { + time = "2025-03-11T02:34:43+00:00"; + condition = config.programs.zsh.enable; + message = '' + A new module is available: 'programs.zsh.initContent'. + + initContent option allows you to set the content of the zshrc file, + you can use `lib.mkOrder` to specify the order of the content you want to insert. + ''; + } + { + time = "2025-03-19T18:10:56+00:00"; + condition = config.services.easyeffects.enable; + message = '' + The Easyeffects module now supports adding json formatted presets + under '$XDG_CONFIG_HOME/easyeffects/{input,output}/'. + ''; + } + + { + time = "2025-02-12T15:56:00+00:00"; + message = '' + A new module is available: 'programs.tex-fmt'. + + tex-fmt is a LaTeX formatter written in Rust. + See https://github.com/WGUNDERWOOD/tex-fmt for more information. + ''; + } + + { + time = "2025-03-24T22:31:45+00:00"; + message = '' + The following default values change from 'true' to + 'false': + + - programs.zellij.enableBashIntegration + - programs.zellij.enableFishIntegration + - programs.zellij.enableZshIntegration + ''; + } + + { + time = "2025-01-02T11:21:19+00:00"; + message = '' + A new module is available: 'services.mpdscribble'. + + A MPD client which submits information about tracks being played to a + scrobbler (e.g. last.fm) + ''; + } ]; }; } diff --git a/modules/misc/nixpkgs-disabled.nix b/modules/misc/nixpkgs-disabled.nix index 70574521a..b7e143d97 100644 --- a/modules/misc/nixpkgs-disabled.nix +++ b/modules/misc/nixpkgs-disabled.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.nixpkgs; @@ -17,28 +15,28 @@ let let lhs = optCall lhs_ { inherit pkgs; }; rhs = optCall rhs_ { inherit pkgs; }; - in lhs // rhs // optionalAttrs (lhs ? packageOverrides) { + in lhs // rhs // lib.optionalAttrs (lhs ? packageOverrides) { packageOverrides = pkgs: optCall lhs.packageOverrides pkgs - // optCall (attrByPath [ "packageOverrides" ] ({ }) rhs) pkgs; - } // optionalAttrs (lhs ? perlPackageOverrides) { + // optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs; + } // lib.optionalAttrs (lhs ? perlPackageOverrides) { perlPackageOverrides = pkgs: optCall lhs.perlPackageOverrides pkgs - // optCall (attrByPath [ "perlPackageOverrides" ] ({ }) rhs) pkgs; + // optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs; }; # Copied from nixpkgs.nix. - configType = mkOptionType { + configType = lib.mkOptionType { name = "nixpkgs-config"; description = "nixpkgs config"; check = x: let traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false; in traceXIfNot isConfig; - merge = args: fold (def: mergeConfig def.value) { }; + merge = args: lib.fold (def: mergeConfig def.value) { }; }; # Copied from nixpkgs.nix. - overlayType = mkOptionType { + overlayType = lib.mkOptionType { name = "nixpkgs-overlay"; description = "nixpkgs overlay"; check = builtins.isFunction; @@ -46,18 +44,18 @@ let }; in { - meta.maintainers = with maintainers; [ thiagokokada ]; + meta.maintainers = with lib.maintainers; [ thiagokokada ]; options.nixpkgs = { - config = mkOption { + config = lib.mkOption { default = null; - type = types.nullOr configType; + type = lib.types.nullOr configType; visible = false; }; - overlays = mkOption { + overlays = lib.mkOption { default = null; - type = types.nullOr (types.listOf overlayType); + type = lib.types.nullOr (lib.types.listOf overlayType); visible = false; }; }; @@ -73,7 +71,7 @@ in { } ]; - warnings = optional ((cfg.config != null) || (cfg.overlays != null)) '' + warnings = lib.optional ((cfg.config != null) || (cfg.overlays != null)) '' You have set either `nixpkgs.config` or `nixpkgs.overlays` while using `home-manager.useGlobalPkgs`. This will soon not be possible. Please remove all `nixpkgs` options when using `home-manager.useGlobalPkgs`. ''; diff --git a/modules/misc/nixpkgs.nix b/modules/misc/nixpkgs.nix index 971491af4..b21e97db9 100644 --- a/modules/misc/nixpkgs.nix +++ b/modules/misc/nixpkgs.nix @@ -2,8 +2,6 @@ { config, lib, pkgs, pkgsPath, ... }: -with lib; - let isConfig = x: builtins.isAttrs x || builtins.isFunction x; @@ -14,40 +12,40 @@ let let lhs = optCall lhs_ { inherit pkgs; }; rhs = optCall rhs_ { inherit pkgs; }; - in lhs // rhs // optionalAttrs (lhs ? packageOverrides) { + in lhs // rhs // lib.optionalAttrs (lhs ? packageOverrides) { packageOverrides = pkgs: optCall lhs.packageOverrides pkgs - // optCall (attrByPath [ "packageOverrides" ] ({ }) rhs) pkgs; - } // optionalAttrs (lhs ? perlPackageOverrides) { + // optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs; + } // lib.optionalAttrs (lhs ? perlPackageOverrides) { perlPackageOverrides = pkgs: optCall lhs.perlPackageOverrides pkgs - // optCall (attrByPath [ "perlPackageOverrides" ] ({ }) rhs) pkgs; + // optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs; }; - configType = mkOptionType { + configType = lib.mkOptionType { name = "nixpkgs-config"; description = "nixpkgs config"; check = x: let traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false; in traceXIfNot isConfig; - merge = args: fold (def: mergeConfig def.value) { }; + merge = args: lib.fold (def: mergeConfig def.value) { }; }; - overlayType = mkOptionType { + overlayType = lib.mkOptionType { name = "nixpkgs-overlay"; description = "nixpkgs overlay"; check = lib.isFunction; merge = lib.mergeOneOption; }; - _pkgs = import pkgsPath (filterAttrs (n: v: v != null) config.nixpkgs); + _pkgs = import pkgsPath (lib.filterAttrs (n: v: v != null) config.nixpkgs); in { options.nixpkgs = { - config = mkOption { + config = lib.mkOption { default = null; example = { allowBroken = true; }; - type = types.nullOr configType; + type = lib.types.nullOr configType; description = '' The configuration of the Nix Packages collection. (For details, see the Nixpkgs documentation.) It allows you to set @@ -72,9 +70,9 @@ in { ''; }; - overlays = mkOption { + overlays = lib.mkOption { default = null; - example = literalExpression '' + example = lib.literalExpression '' [ (final: prev: { openssh = prev.openssh.override { @@ -85,7 +83,7 @@ in { }) ] ''; - type = types.nullOr (types.listOf overlayType); + type = lib.types.nullOr (lib.types.listOf overlayType); description = '' List of overlays to use with the Nix Packages collection. (For details, see the Nixpkgs documentation.) It allows you to @@ -105,8 +103,8 @@ in { ''; }; - system = mkOption { - type = types.str; + system = lib.mkOption { + type = lib.types.str; example = "i686-linux"; internal = true; description = '' @@ -123,7 +121,7 @@ in { _module.args = { # We use a no-op override to make sure that the option can be merged without evaluating # `_pkgs`, see https://github.com/nix-community/home-manager/pull/993 - pkgs = mkOverride modules.defaultOverridePriority _pkgs; + pkgs = lib.mkOverride lib.modules.defaultOverridePriority _pkgs; pkgs_i686 = if _pkgs.stdenv.isLinux && _pkgs.stdenv.hostPlatform.isx86 then _pkgs.pkgsi686Linux diff --git a/modules/misc/numlock.nix b/modules/misc/numlock.nix index 88032417f..e453a0951 100644 --- a/modules/misc/numlock.nix +++ b/modules/misc/numlock.nix @@ -1,25 +1,24 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.xsession.numlock; in { - meta.maintainers = [ maintainers.evanjs ]; + meta.maintainers = [ lib.maintainers.evanjs ]; - options = { xsession.numlock.enable = mkEnableOption "Num Lock"; }; + options = { xsession.numlock.enable = lib.mkEnableOption "Num Lock"; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ - (hm.assertions.assertPlatform "xsession.numlock" pkgs platforms.linux) + (lib.hm.assertions.assertPlatform "xsession.numlock" pkgs + lib.platforms.linux) ]; systemd.user.services.numlockx = { Unit = { Description = "NumLockX"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/misc/pam.nix b/modules/misc/pam.nix index 22a5daf0d..bf0af355f 100644 --- a/modules/misc/pam.nix +++ b/modules/misc/pam.nix @@ -1,18 +1,16 @@ -{ config, lib, pkgs, ... }: - -with lib; +{ config, lib, ... }: let cfg = config.pam; in { - meta.maintainers = with maintainers; [ rycee veehaitch ]; + meta.maintainers = with lib.maintainers; [ rycee veehaitch ]; options = { - pam.sessionVariables = mkOption { + pam.sessionVariables = lib.mkOption { default = { }; - type = types.attrs; + type = lib.types.attrs; example = { EDITOR = "vim"; }; description = '' Environment variables that will be set for the PAM session. @@ -25,10 +23,10 @@ in { }; pam.yubico.authorizedYubiKeys = { - ids = mkOption { - type = with types; + ids = lib.mkOption { + type = with lib.types; let - yubiKeyId = addCheck str (s: stringLength s == 12) // { + yubiKeyId = addCheck str (s: lib.stringLength s == 12) // { name = "yubiKeyId"; description = "string of length 12"; }; @@ -41,8 +39,8 @@ in { ''; }; - path = mkOption { - type = types.str; + path = lib.mkOption { + type = lib.types.str; default = ".yubico/authorized_yubikeys"; description = '' File path to write the authorized YubiKeys, @@ -52,16 +50,16 @@ in { }; }; - config = mkMerge [ - (mkIf (cfg.sessionVariables != { }) { - home.file.".pam_environment".text = concatStringsSep "\n" - (mapAttrsToList (n: v: ''${n} OVERRIDE="${toString v}"'') + config = lib.mkMerge [ + (lib.mkIf (cfg.sessionVariables != { }) { + home.file.".pam_environment".text = lib.concatStringsSep "\n" + (lib.mapAttrsToList (n: v: ''${n} OVERRIDE="${toString v}"'') cfg.sessionVariables) + "\n"; }) - (mkIf (cfg.yubico.authorizedYubiKeys.ids != [ ]) { + (lib.mkIf (cfg.yubico.authorizedYubiKeys.ids != [ ]) { home.file.${cfg.yubico.authorizedYubiKeys.path}.text = - concatStringsSep ":" + lib.concatStringsSep ":" ([ config.home.username ] ++ cfg.yubico.authorizedYubiKeys.ids); }) ]; diff --git a/modules/misc/qt.nix b/modules/misc/qt.nix index 3152e0091..41cd660fc 100644 --- a/modules/misc/qt.nix +++ b/modules/misc/qt.nix @@ -13,6 +13,11 @@ let libsForQt5.plasma-integration libsForQt5.systemsettings ]; + kde6 = [ + kdePackages.kio + kdePackages.plasma-integration + kdePackages.systemsettings + ]; lxqt = [ lxqt.lxqt-qtplugin lxqt.lxqt-config ]; qtct = [ libsForQt5.qt5ct qt6Packages.qt6ct ]; }; @@ -21,6 +26,7 @@ let styleNames = { gtk = "gtk2"; qtct = "qt5ct"; + kde6 = "kde"; }; # Maps known lowercase style names to style packages. Non-exhaustive. @@ -75,6 +81,8 @@ in { [ "libsForQt5" "qt5ct" ] [ "libsForQt5" "qtstyleplugins" ] [ "libsForQt5" "systemsettings" ] + [ "kdePackages" "plasma-integration" ] + [ "kdePackages" "systemsettings" ] [ "lxqt" "lxqt-config" ] [ "lxqt" "lxqt-qtplugin" ] [ "qt6Packages" "qt6ct" ] @@ -114,7 +122,10 @@ in { applications `kde` - : Use Qt settings from Plasma + : Use Qt settings from Plasma 5 + + `kde6` + : Use Qt settings from Plasma 6 ''; }; package = lib.mkOption { @@ -131,8 +142,8 @@ in { }; in lib.mkOption { type = with lib.types; - nullOr - (either (enum [ "gtk" "gtk3" "gnome" "adwaita" "lxqt" "qtct" "kde" ]) + nullOr (either + (enum [ "gtk" "gtk3" "gnome" "adwaita" "lxqt" "qtct" "kde" "kde6" ]) (lib.types.submodule { options = newOption; })); default = null; description = '' @@ -218,13 +229,10 @@ in { inherit (config.home) profileDirectory; qtVersions = with pkgs; [ qt5 qt6 ]; makeQtPath = prefix: - lib.concatStringsSep ":" (map (qt: "${profileDirectory}/${qt.qtbase.${prefix}}") qtVersions); in { - QT_PLUGIN_PATH = "$QT_PLUGIN_PATH\${QT_PLUGIN_PATH:+:}" - + (makeQtPath "qtPluginPrefix"); - QML2_IMPORT_PATH = "$QML2_IMPORT_PATH\${QML2_IMPORT_PATH:+:}" - + (makeQtPath "qtQmlPrefix"); + QT_PLUGIN_PATH = makeQtPath "qtPluginPrefix"; + QML2_IMPORT_PATH = makeQtPath "qtQmlPrefix"; }; in lib.mkIf cfg.enable { @@ -248,19 +256,14 @@ in { home = { sessionVariables = envVars; - # home.sessionVariables does not support setting the same environment - # variable to different values. - # Since some other modules may set the QT_PLUGIN_PATH or QML2_IMPORT_PATH - # to their own value, e.g.: fcitx5, we avoid conflicts by setting - # the values in home.sessionVariablesExtra instead. - sessionVariablesExtra = '' - export QT_PLUGIN_PATH=${envVarsExtra.QT_PLUGIN_PATH} - export QML2_IMPORT_PATH=${envVarsExtra.QML2_IMPORT_PATH} - ''; + sessionSearchVariables = envVarsExtra; }; # Apply theming also to apps started by systemd. - systemd.user.sessionVariables = envVars // envVarsExtra; + systemd.user.sessionVariables = envVars // { + QT_PLUGIN_PATH = lib.concatStringsSep ":" envVarsExtra.QT_PLUGIN_PATH; + QML2_IMPORT_PATH = lib.concatStringsSep ":" envVarsExtra.QML2_IMPORT_PATH; + }; home.packages = (lib.findFirst (x: x != [ ]) [ ] [ (lib.optionals (platformTheme.package != null) diff --git a/modules/misc/specialisation.nix b/modules/misc/specialisation.nix index dc5f78e14..95adc998f 100644 --- a/modules/misc/specialisation.nix +++ b/modules/misc/specialisation.nix @@ -1,27 +1,25 @@ { config, name, extendModules, lib, ... }: -with lib; - { imports = - [ (mkRenamedOptionModule [ "specialization" ] [ "specialisation" ]) ]; + [ (lib.mkRenamedOptionModule [ "specialization" ] [ "specialisation" ]) ]; - options.specialisation = mkOption { - type = types.attrsOf (types.submodule { + options.specialisation = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule { options = { - configuration = mkOption { + configuration = lib.mkOption { type = let extended = extendModules { modules = [{ # Prevent infinite recursion - specialisation = mkOverride 0 { }; + specialisation = lib.mkOverride 0 { }; # If used inside the NixOS/nix-darwin module, we get conflicting definitions # of `name` inside the specialisation: one is the user name coming from the # NixOS module definition and the other is `configuration`, the name of this # option. Thus we need to explicitly wire the former into the module arguments. # See discussion at https://github.com/nix-community/home-manager/issues/3716 - _module.args.name = mkForce name; + _module.args.name = lib.mkForce name; }]; }; in extended.type; @@ -70,14 +68,21 @@ with lib; ''; }; - config = mkIf (config.specialisation != { }) { + config = lib.mkIf (config.specialisation != { }) { + assertions = map (n: { + assertion = !lib.hasInfix "/" n; + message = + " in specialisation. cannot contain a forward slash."; + }) (lib.attrNames config.specialisation); + home.extraBuilderCommands = let link = n: v: let pkg = v.configuration.home.activationPackage; - in "ln -s ${pkg} $out/specialisation/${n}"; + in "ln -s ${pkg} $out/specialisation/${lib.escapeShellArg n}"; in '' mkdir $out/specialisation - ${concatStringsSep "\n" (mapAttrsToList link config.specialisation)} + ${lib.concatStringsSep "\n" + (lib.mapAttrsToList link config.specialisation)} ''; }; } diff --git a/modules/misc/submodule-support.nix b/modules/misc/submodule-support.nix index 82fbc0a30..b42bc4870 100644 --- a/modules/misc/submodule-support.nix +++ b/modules/misc/submodule-support.nix @@ -1,13 +1,11 @@ { lib, ... }: -with lib; - { - meta.maintainers = [ maintainers.rycee ]; + meta.maintainers = [ lib.maintainers.rycee ]; options.submoduleSupport = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; internal = true; description = '' @@ -16,8 +14,8 @@ with lib; ''; }; - externalPackageInstall = mkOption { - type = types.bool; + externalPackageInstall = lib.mkOption { + type = lib.types.bool; default = false; internal = true; description = '' @@ -39,9 +37,9 @@ with lib; # module system can not inform modules about their non-existence; see # https://github.com/NixOS/nixpkgs/issues/311709#issuecomment-2110861842 _module.args = { - osConfig = mkDefault null; - nixosConfig = mkDefault null; - darwinConfig = mkDefault null; + osConfig = lib.mkDefault null; + nixosConfig = lib.mkDefault null; + darwinConfig = lib.mkDefault null; }; }; } diff --git a/modules/misc/tmpfiles.nix b/modules/misc/tmpfiles.nix index 9fa072b89..f9debf543 100644 --- a/modules/misc/tmpfiles.nix +++ b/modules/misc/tmpfiles.nix @@ -1,16 +1,14 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.systemd.user.tmpfiles; in { - meta.maintainers = [ maintainers.dawidsowa ]; + meta.maintainers = [ lib.maintainers.dawidsowa ]; - options.systemd.user.tmpfiles.rules = mkOption { - type = types.listOf types.str; + options.systemd.user.tmpfiles.rules = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "L /home/user/Documents - - - - /mnt/data/Documents" ]; description = '' @@ -21,10 +19,10 @@ in { ''; }; - config = mkIf (cfg.rules != [ ]) { + config = lib.mkIf (cfg.rules != [ ]) { assertions = [ - (hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs - platforms.linux) + (lib.hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs + lib.platforms.linux) ]; xdg.configFile = { @@ -32,7 +30,7 @@ in { text = '' # This file is created automatically and should not be modified. # Please change the option ‘systemd.user.tmpfiles.rules’ instead. - ${concatStringsSep "\n" cfg.rules} + ${lib.concatStringsSep "\n" cfg.rules} ''; onChange = "${pkgs.systemd}/bin/systemd-tmpfiles --user --create"; }; diff --git a/modules/misc/uninstall.nix b/modules/misc/uninstall.nix index 3086d21b8..4fe26326e 100644 --- a/modules/misc/uninstall.nix +++ b/modules/misc/uninstall.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, lib, ... }: let diff --git a/modules/misc/version.nix b/modules/misc/version.nix index 176901f3e..3c7317360 100644 --- a/modules/misc/version.nix +++ b/modules/misc/version.nix @@ -1,12 +1,13 @@ { config, lib, ... }: -with lib; +let + inherit (lib) types; -let releaseInfo = lib.importJSON ../../release.json; + releaseInfo = lib.importJSON ../../release.json; in { options = { - home.stateVersion = mkOption { + home.stateVersion = lib.mkOption { type = types.enum [ "18.09" "19.03" @@ -39,20 +40,20 @@ in { }; home.version = { - full = mkOption { + full = lib.mkOption { internal = true; readOnly = true; type = types.str; default = let inherit (config.home.version) release revision; - suffix = - optionalString (revision != null) "+${substring 0 8 revision}"; + suffix = lib.optionalString (revision != null) + "+${lib.substring 0 8 revision}"; in "${release}${suffix}"; example = "22.11+213a0629"; description = "The full Home Manager version."; }; - release = mkOption { + release = lib.mkOption { internal = true; readOnly = true; type = types.str; @@ -61,7 +62,7 @@ in { description = "The Home Manager release."; }; - isReleaseBranch = mkOption { + isReleaseBranch = lib.mkOption { internal = true; readOnly = true; type = types.bool; @@ -72,11 +73,14 @@ in { ''; }; - revision = mkOption { + revision = lib.mkOption { internal = true; type = types.nullOr types.str; default = let gitRepo = "${toString ./../..}/.git"; - in if pathIsGitRepo gitRepo then commitIdFromGitRepo gitRepo else null; + in if lib.pathIsGitRepo gitRepo then + lib.commitIdFromGitRepo gitRepo + else + null; description = '' The Git revision from which this Home Manager configuration was built. ''; diff --git a/modules/misc/vte.nix b/modules/misc/vte.nix index fbe38c016..09862b41b 100644 --- a/modules/misc/vte.nix +++ b/modules/misc/vte.nix @@ -1,9 +1,7 @@ { config, lib, pkgs, ... }: -with lib; - { - meta.maintainers = [ maintainers.rycee ]; + meta.maintainers = [ lib.maintainers.rycee ]; options.programs = let description = '' @@ -12,13 +10,17 @@ with lib; directory. ''; in { - bash.enableVteIntegration = mkEnableOption "" // { inherit description; }; + bash.enableVteIntegration = lib.mkEnableOption "" // { + inherit description; + }; - zsh.enableVteIntegration = mkEnableOption "" // { inherit description; }; + zsh.enableVteIntegration = lib.mkEnableOption "" // { + inherit description; + }; }; - config = mkMerge [ - (mkIf config.programs.bash.enableVteIntegration { + config = lib.mkMerge [ + (lib.mkIf config.programs.bash.enableVteIntegration { # Unfortunately we have to do a little dance here to fix two # problems with the upstream vte.sh file: # @@ -42,8 +44,8 @@ with lib; ''; }) - (mkIf config.programs.zsh.enableVteIntegration { - programs.zsh.initExtra = '' + (lib.mkIf config.programs.zsh.enableVteIntegration { + programs.zsh.initContent = '' . ${pkgs.vte}/etc/profile.d/vte.sh ''; }) diff --git a/modules/misc/xdg-desktop-entries.nix b/modules/misc/xdg-desktop-entries.nix index 1aab6ffe7..1bc3ef6b5 100644 --- a/modules/misc/xdg-desktop-entries.nix +++ b/modules/misc/xdg-desktop-entries.nix @@ -1,13 +1,13 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) literalExpression mkOption types; + desktopEntry = { imports = [ - (mkRemovedOptionModule [ "extraConfig" ] + (lib.mkRemovedOptionModule [ "extraConfig" ] "The `extraConfig` option of `xdg.desktopEntries` has been removed following a change in Nixpkgs.") - (mkRemovedOptionModule [ "fileValidation" ] + (lib.mkRemovedOptionModule [ "fileValidation" ] "Validation of the desktop file is always enabled.") ]; options = { @@ -172,12 +172,12 @@ let type exec icon comment terminal genericName startupNotify noDisplay prefersNonDefaultGPU actions; desktopName = config.name; - mimeTypes = optionals (config.mimeType != null) config.mimeType; - categories = optionals (config.categories != null) config.categories; + mimeTypes = lib.optionals (config.mimeType != null) config.mimeType; + categories = lib.optionals (config.categories != null) config.categories; extraConfig = config.settings; }; in { - meta.maintainers = [ hm.maintainers.cwyc ]; + meta.maintainers = [ lib.hm.maintainers.cwyc ]; options.xdg.desktopEntries = mkOption { description = '' @@ -203,13 +203,16 @@ in { ''; }; - config = mkIf (config.xdg.desktopEntries != { }) { + config = lib.mkIf (config.xdg.desktopEntries != { }) { assertions = [ - (hm.assertions.assertPlatform "xdg.desktopEntries" pkgs platforms.linux) - ] ++ flatten (catAttrs "assertions" (attrValues config.xdg.desktopEntries)); + (lib.hm.assertions.assertPlatform "xdg.desktopEntries" pkgs + lib.platforms.linux) + ] ++ lib.flatten + (lib.catAttrs "assertions" (lib.attrValues config.xdg.desktopEntries)); - home.packages = (map hiPrio # we need hiPrio to override existing entries - (attrsets.mapAttrsToList makeFile config.xdg.desktopEntries)); + home.packages = + (map lib.hiPrio # we need hiPrio to override existing entries + (lib.attrsets.mapAttrsToList makeFile config.xdg.desktopEntries)); }; } diff --git a/modules/misc/xdg-mime-apps.nix b/modules/misc/xdg-mime-apps.nix index 39eea478e..6efa43b11 100644 --- a/modules/misc/xdg-mime-apps.nix +++ b/modules/misc/xdg-mime-apps.nix @@ -1,16 +1,15 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) mkOption types; cfg = config.xdg.mimeApps; strListOrSingleton = with types; - coercedTo (either (listOf str) str) toList (listOf str); + coercedTo (either (listOf str) str) lib.toList (listOf str); in { - meta.maintainers = with maintainers; [ euxane ]; + meta.maintainers = with lib.maintainers; [ euxane ]; options.xdg.mimeApps = { enable = mkOption { @@ -29,7 +28,7 @@ in { associations.added = mkOption { type = types.attrsOf strListOrSingleton; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { "mimetype1" = [ "foo1.desktop" "foo2.desktop" "foo3.desktop" ]; "mimetype2" = "foo4.desktop"; @@ -56,7 +55,7 @@ in { defaultApplications = mkOption { type = types.attrsOf strListOrSingleton; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { "mimetype1" = [ "default1.desktop" "default2.desktop" ]; } @@ -71,22 +70,22 @@ in { }; }; - config = mkMerge [ + config = lib.mkMerge [ { # Given a package that installs .desktop files in the usual location, # return a mapping from mime types to lists of desktop file names. This is # suitable for use with `xdg.mimeApps.defaultApplications`. lib.xdg.mimeAssociations = let processLines = str: - zipAttrs - (filter (e: e != null) (map processLine (splitString "\n" str))); + lib.zipAttrs (lib.filter (e: e != null) + (map processLine (lib.splitString "\n" str))); processLine = str: let - entry = splitString ";" str; - k = elemAt entry 0; - v = elemAt entry 1; - in if length entry == 2 then { ${k} = v; } else null; + entry = lib.splitString ";" str; + k = lib.elemAt entry 0; + v = lib.elemAt entry 1; + in if lib.length entry == 2 then { ${k} = v; } else null; associations = ps: pkgs.runCommand "mime-assoc" { inherit ps; } '' @@ -100,17 +99,19 @@ in { in p: processLines (builtins.readFile (associations p)); } - (mkIf cfg.enable { - assertions = - [ (hm.assertions.assertPlatform "xdg.mimeApps" pkgs platforms.linux) ]; + (lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "xdg.mimeApps" pkgs + lib.platforms.linux) + ]; # Deprecated but still used by some applications. xdg.dataFile."applications/mimeapps.list".source = config.xdg.configFile."mimeapps.list".source; xdg.configFile."mimeapps.list".text = - let joinValues = mapAttrs (n: concatStringsSep ";"); - in generators.toINI { } { + let joinValues = lib.mapAttrs (n: lib.concatStringsSep ";"); + in lib.generators.toINI { } { "Added Associations" = joinValues cfg.associations.added; "Removed Associations" = joinValues cfg.associations.removed; "Default Applications" = joinValues cfg.defaultApplications; diff --git a/modules/misc/xdg-mime.nix b/modules/misc/xdg-mime.nix index 78b569fa5..fa22f96df 100644 --- a/modules/misc/xdg-mime.nix +++ b/modules/misc/xdg-mime.nix @@ -1,11 +1,10 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.xdg.mime; - inherit (lib) getExe getExe'; + + inherit (lib) getExe getExe' mkOption types; in { options = { @@ -13,8 +12,8 @@ in { enable = mkOption { type = types.bool; default = pkgs.stdenv.hostPlatform.isLinux; - defaultText = - literalExpression "true if host platform is Linux, false otherwise"; + defaultText = lib.literalExpression + "true if host platform is Linux, false otherwise"; description = '' Whether to install programs and files to support the XDG Shared MIME-info specification and XDG MIME Applications @@ -29,22 +28,23 @@ in { sharedMimeInfoPackage = mkOption { type = types.package; default = pkgs.shared-mime-info; - defaultText = literalExpression "pkgs.shared-mime-info"; + defaultText = lib.literalExpression "pkgs.shared-mime-info"; description = "The package to use when running update-mime-database."; }; desktopFileUtilsPackage = mkOption { type = types.package; default = pkgs.desktop-file-utils; - defaultText = literalExpression "pkgs.desktop-file-utils"; + defaultText = lib.literalExpression "pkgs.desktop-file-utils"; description = "The package to use when running update-desktop-database."; }; }; }; - config = mkIf cfg.enable { - assertions = - [ (hm.assertions.assertPlatform "xdg.mime" pkgs platforms.linux) ]; + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "xdg.mime" pkgs lib.platforms.linux) + ]; home.packages = [ # Explicitly install package to provide basic mime types. @@ -63,15 +63,19 @@ in { if [[ -w $out/share/mime && -w $out/share/mime/packages && -d $out/share/mime/packages ]]; then XDG_DATA_DIRS=$out/share \ PKGSYSTEM_ENABLE_FSYNC=0 \ - ${getExe cfg.sharedMimeInfoPackage} \ - -V $out/share/mime > /dev/null + ${ + getExe + (cfg.sharedMimeInfoPackage.__spliced.buildHost or cfg.sharedMimeInfoPackage) + } -V $out/share/mime > /dev/null fi if [[ -w $out/share/applications ]]; then - ${getExe' cfg.desktopFileUtilsPackage "update-desktop-database"} \ - $out/share/applications + ${ + getExe' + (cfg.desktopFileUtilsPackage.__spliced.buildHost or cfg.desktopFileUtilsPackage) + "update-desktop-database" + } $out/share/applications fi ''; }; - } diff --git a/modules/misc/xdg-system-dirs.nix b/modules/misc/xdg-system-dirs.nix index 0be5e26d2..d02cff71d 100644 --- a/modules/misc/xdg-system-dirs.nix +++ b/modules/misc/xdg-system-dirs.nix @@ -1,33 +1,32 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) types; cfg = config.xdg.systemDirs; - configDirs = concatStringsSep ":" cfg.config; + configDirs = lib.concatStringsSep ":" cfg.config; - dataDirs = concatStringsSep ":" cfg.data; + dataDirs = lib.concatStringsSep ":" cfg.data; in { - meta.maintainers = with maintainers; [ tadfisher ]; + meta.maintainers = with lib.maintainers; [ tadfisher ]; options.xdg.systemDirs = { - config = mkOption { + config = lib.mkOption { type = types.listOf types.str; default = [ ]; - example = literalExpression ''[ "/etc/xdg" ]''; + example = lib.literalExpression ''[ "/etc/xdg" ]''; description = '' Directory names to add to {env}`XDG_CONFIG_DIRS` in the user session. ''; }; - data = mkOption { + data = lib.mkOption { type = types.listOf types.str; default = [ ]; - example = literalExpression ''[ "/usr/share" "/usr/local/share" ]''; + example = lib.literalExpression ''[ "/usr/share" "/usr/local/share" ]''; description = '' Directory names to add to {env}`XDG_DATA_DIRS` in the user session. @@ -35,14 +34,15 @@ in { }; }; - config = mkMerge [ - (mkIf (cfg.config != [ ] || cfg.data != [ ]) { + config = lib.mkMerge [ + (lib.mkIf (cfg.config != [ ] || cfg.data != [ ]) { assertions = [ - (hm.assertions.assertPlatform "xdg.systemDirs" pkgs platforms.linux) + (lib.hm.assertions.assertPlatform "xdg.systemDirs" pkgs + lib.platforms.linux) ]; }) - (mkIf (cfg.config != [ ]) { + (lib.mkIf (cfg.config != [ ]) { home.sessionVariables.XDG_CONFIG_DIRS = "${configDirs}\${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}"; @@ -50,7 +50,7 @@ in { "${configDirs}\${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}"; }) - (mkIf (cfg.data != [ ]) { + (lib.mkIf (cfg.data != [ ]) { home.sessionVariables.XDG_DATA_DIRS = "${dataDirs}\${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}"; diff --git a/modules/misc/xdg-user-dirs.nix b/modules/misc/xdg-user-dirs.nix index 5281203b9..b693118ad 100644 --- a/modules/misc/xdg-user-dirs.nix +++ b/modules/misc/xdg-user-dirs.nix @@ -1,16 +1,15 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) literalExpression mkOption types; cfg = config.xdg.userDirs; in { - meta.maintainers = with maintainers; [ euxane ]; + meta.maintainers = with lib.maintainers; [ euxane ]; imports = [ - (mkRenamedOptionModule [ "xdg" "userDirs" "publishShare" ] [ + (lib.mkRenamedOptionModule [ "xdg" "userDirs" "publishShare" ] [ "xdg" "userDirs" "publicShare" @@ -108,11 +107,11 @@ in { }; createDirectories = - mkEnableOption "automatic creation of the XDG user directories"; + lib.mkEnableOption "automatic creation of the XDG user directories"; }; config = let - directories = (filterAttrs (n: v: !isNull v) { + directories = (lib.filterAttrs (n: v: !isNull v) { XDG_DESKTOP_DIR = cfg.desktop; XDG_DOCUMENTS_DIR = cfg.documents; XDG_DOWNLOAD_DIR = cfg.download; @@ -122,24 +121,26 @@ in { XDG_TEMPLATES_DIR = cfg.templates; XDG_VIDEOS_DIR = cfg.videos; }) // cfg.extraConfig; - in mkIf cfg.enable { - assertions = - [ (hm.assertions.assertPlatform "xdg.userDirs" pkgs platforms.linux) ]; + in lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "xdg.userDirs" pkgs lib.platforms.linux) + ]; xdg.configFile."user-dirs.dirs".text = let # For some reason, these need to be wrapped with quotes to be valid. - wrapped = mapAttrs (_: value: ''"${value}"'') directories; - in generators.toKeyValue { } wrapped; + wrapped = lib.mapAttrs (_: value: ''"${value}"'') directories; + in lib.generators.toKeyValue { } wrapped; xdg.configFile."user-dirs.conf".text = "enabled=False"; home.sessionVariables = directories; - home.activation.createXdgUserDirectories = mkIf cfg.createDirectories (let - directoriesList = attrValues directories; - mkdir = - (dir: ''[[ -L "${dir}" ]] || run mkdir -p $VERBOSE_ARG "${dir}"''); - in lib.hm.dag.entryAfter [ "linkGeneration" ] - (strings.concatMapStringsSep "\n" mkdir directoriesList)); + home.activation.createXdgUserDirectories = lib.mkIf cfg.createDirectories + (let + directoriesList = lib.attrValues directories; + mkdir = + (dir: ''[[ -L "${dir}" ]] || run mkdir -p $VERBOSE_ARG "${dir}"''); + in lib.hm.dag.entryAfter [ "linkGeneration" ] + (lib.strings.concatMapStringsSep "\n" mkdir directoriesList)); }; } diff --git a/modules/misc/xdg.nix b/modules/misc/xdg.nix index b916e88fb..e309462e7 100644 --- a/modules/misc/xdg.nix +++ b/modules/misc/xdg.nix @@ -1,8 +1,7 @@ -{ options, config, lib, pkgs, ... }: - -with lib; +{ config, lib, pkgs, ... }: let + inherit (lib) mkOptionDefault mkIf mkOption types; cfg = config.xdg; @@ -22,7 +21,16 @@ let in { options.xdg = { - enable = mkEnableOption "management of XDG base directories"; + enable = lib.mkEnableOption "management of XDG base directories"; + + cacheFile = mkOption { + type = fileType "xdg.cacheFile" "{var}`xdg.cacheHome`" cfg.cacheHome; + default = { }; + description = '' + Attribute set of files to link into the user's XDG + cache home. + ''; + }; cacheHome = mkOption { type = types.path; @@ -98,7 +106,7 @@ in { }; }; - config = mkMerge [ + config = lib.mkMerge [ (let variables = { XDG_CACHE_HOME = cfg.cacheHome; @@ -107,10 +115,10 @@ in { XDG_STATE_HOME = cfg.stateHome; }; in mkIf cfg.enable { - xdg.cacheHome = mkDefault defaultCacheHome; - xdg.configHome = mkDefault defaultConfigHome; - xdg.dataHome = mkDefault defaultDataHome; - xdg.stateHome = mkDefault defaultStateHome; + xdg.cacheHome = mkOptionDefault defaultCacheHome; + xdg.configHome = mkOptionDefault defaultConfigHome; + xdg.dataHome = mkOptionDefault defaultDataHome; + xdg.stateHome = mkOptionDefault defaultStateHome; home.sessionVariables = variables; systemd.user.sessionVariables = @@ -118,31 +126,41 @@ in { }) # Legacy non-deterministic setup. - (mkIf (!cfg.enable && versionOlder config.home.stateVersion "20.09") { + (mkIf (!cfg.enable && lib.versionOlder config.home.stateVersion "20.09") { xdg.cacheHome = - mkDefault (getEnvFallback "XDG_CACHE_HOME" defaultCacheHome); + mkOptionDefault (getEnvFallback "XDG_CACHE_HOME" defaultCacheHome); xdg.configHome = - mkDefault (getEnvFallback "XDG_CONFIG_HOME" defaultConfigHome); - xdg.dataHome = mkDefault (getEnvFallback "XDG_DATA_HOME" defaultDataHome); + mkOptionDefault (getEnvFallback "XDG_CONFIG_HOME" defaultConfigHome); + xdg.dataHome = + mkOptionDefault (getEnvFallback "XDG_DATA_HOME" defaultDataHome); + xdg.stateHome = + mkOptionDefault (getEnvFallback "XDG_STATE_HOME" defaultStateHome); }) # "Modern" deterministic setup. - (mkIf (!cfg.enable && versionAtLeast config.home.stateVersion "20.09") { - xdg.cacheHome = mkDefault defaultCacheHome; - xdg.configHome = mkDefault defaultConfigHome; - xdg.dataHome = mkDefault defaultDataHome; - xdg.stateHome = mkDefault defaultStateHome; + (mkIf (!cfg.enable && lib.versionAtLeast config.home.stateVersion "20.09") { + xdg.cacheHome = mkOptionDefault defaultCacheHome; + xdg.configHome = mkOptionDefault defaultConfigHome; + xdg.dataHome = mkOptionDefault defaultDataHome; + xdg.stateHome = mkOptionDefault defaultStateHome; }) { - home.file = mkMerge [ - (mapAttrs' (name: file: nameValuePair "${cfg.configHome}/${name}" file) + home.file = lib.mkMerge [ + (lib.mapAttrs' + (name: file: lib.nameValuePair "${cfg.cacheHome}/${name}" file) + cfg.cacheFile) + (lib.mapAttrs' + (name: file: lib.nameValuePair "${cfg.configHome}/${name}" file) cfg.configFile) - (mapAttrs' (name: file: nameValuePair "${cfg.dataHome}/${name}" file) + (lib.mapAttrs' + (name: file: lib.nameValuePair "${cfg.dataHome}/${name}" file) cfg.dataFile) - (mapAttrs' (name: file: nameValuePair "${cfg.stateHome}/${name}" file) + (lib.mapAttrs' + (name: file: lib.nameValuePair "${cfg.stateHome}/${name}" file) cfg.stateFile) { "${cfg.cacheHome}/.keep".text = ""; } + { "${cfg.stateHome}/.keep".text = ""; } ]; } ]; diff --git a/modules/misc/xfconf.nix b/modules/misc/xfconf.nix index 087040085..b95413676 100644 --- a/modules/misc/xfconf.nix +++ b/modules/misc/xfconf.nix @@ -1,8 +1,7 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) mkOption types; cfg = config.xfconf; @@ -51,12 +50,12 @@ let "-s" v ] else if builtins.isList v then - [ "-a" ] ++ concatMap withType v + [ "-a" ] ++ lib.concatMap withType v else throw "unexpected xfconf type: ${builtins.typeOf v}"; in { - meta.maintainers = [ maintainers.chuangzhu ]; + meta.maintainers = [ lib.maintainers.chuangzhu ]; options.xfconf = { enable = mkOption { @@ -81,7 +80,7 @@ in { description = "xfconf settings"; }; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { xfce4-session = { "startup/ssh-agent/enabled" = false; @@ -99,16 +98,16 @@ in { }; }; - config = mkIf (cfg.enable && cfg.settings != { }) { + config = lib.mkIf (cfg.enable && cfg.settings != { }) { assertions = - [ (hm.assertions.assertPlatform "xfconf" pkgs platforms.linux) ]; + [ (lib.hm.assertions.assertPlatform "xfconf" pkgs lib.platforms.linux) ]; - home.activation.xfconfSettings = hm.dag.entryAfter [ "installPackages" ] + home.activation.xfconfSettings = lib.hm.dag.entryAfter [ "installPackages" ] (let mkCommand = channel: property: value: '' run ${pkgs.xfce.xfconf}/bin/xfconf-query \ ${ - escapeShellArgs ([ "-c" channel "-p" "/${property}" ] + lib.escapeShellArgs ([ "-c" channel "-p" "/${property}" ] ++ (if value == null then [ "-r" ] else @@ -116,13 +115,12 @@ in { } ''; - commands = mapAttrsToList - (channel: properties: mapAttrsToList (mkCommand channel) properties) - cfg.settings; + commands = lib.mapAttrsToList (channel: properties: + lib.mapAttrsToList (mkCommand channel) properties) cfg.settings; load = pkgs.writeShellScript "load-xfconf" '' ${config.lib.bash.initHomeManagerLib} - ${concatMapStrings concatStrings commands} + ${lib.concatMapStrings lib.concatStrings commands} ''; in '' if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then diff --git a/modules/modules.nix b/modules/modules.nix index 28fb3450a..5c277d733 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -9,8 +9,6 @@ # If disabled, the pkgs attribute passed to this function is used instead. , useNixpkgsModule ? true }: -with lib; - let modules = [ @@ -30,6 +28,7 @@ let ./misc/fontconfig.nix ./misc/gtk.nix ./misc/lib.nix + ./misc/mozilla-messaging-hosts.nix ./misc/news.nix ./misc/nixgl.nix ./misc/numlock.nix @@ -89,6 +88,8 @@ let ./programs/dircolors.nix ./programs/direnv.nix ./programs/discocss.nix + ./programs/distrobox.nix + ./programs/earthly.nix ./programs/eclipse.nix ./programs/emacs.nix ./programs/eww.nix @@ -131,6 +132,7 @@ let ./programs/i3blocks.nix ./programs/i3status-rust.nix ./programs/i3status.nix + ./programs/iamb.nix ./programs/imv.nix ./programs/info.nix ./programs/ion.nix @@ -138,6 +140,7 @@ let ./programs/java.nix ./programs/jetbrains-remote.nix ./programs/jq.nix + ./programs/jqp.nix ./programs/jujutsu.nix ./programs/joshuto.nix ./programs/joplin-desktop.nix @@ -151,6 +154,7 @@ let ./programs/kodi.nix ./programs/kubecolor.nix ./programs/lapce.nix + ./programs/lazydocker.nix ./programs/lazygit.nix ./programs/ledger.nix ./programs/less.nix @@ -166,8 +170,10 @@ let ./programs/mbsync.nix ./programs/mcfly.nix ./programs/mercurial.nix + ./programs/mergiraf.nix ./programs/micro.nix ./programs/mise.nix + ./programs/mods.nix ./programs/mpv.nix ./programs/mr.nix ./programs/msmtp.nix @@ -193,6 +199,7 @@ let ./programs/octant.nix ./programs/offlineimap.nix ./programs/oh-my-posh.nix + ./programs/onlyoffice.nix ./programs/opam.nix ./programs/openstackclient.nix ./programs/pandoc.nix @@ -215,9 +222,11 @@ let ./programs/qutebrowser.nix ./programs/ranger.nix ./programs/rbw.nix + ./programs/rclone.nix ./programs/readline.nix ./programs/rio.nix ./programs/ripgrep.nix + ./programs/ripgrep-all.nix ./programs/rofi-pass.nix ./programs/rofi.nix ./programs/rtorrent.nix @@ -236,12 +245,14 @@ let ./programs/sqls.nix ./programs/ssh.nix ./programs/starship.nix + ./programs/swayimg.nix ./programs/swaylock.nix ./programs/swayr.nix ./programs/taskwarrior.nix ./programs/tealdeer.nix ./programs/terminator.nix ./programs/termite.nix + ./programs/tex-fmt.nix ./programs/texlive.nix ./programs/thefuck.nix ./programs/thunderbird.nix @@ -259,16 +270,17 @@ let ./programs/vifm.nix ./programs/vim-vint.nix ./programs/vim.nix + ./programs/vinegar.nix ./programs/vscode.nix ./programs/vscode/haskell.nix ./programs/pywal.nix ./programs/rbenv.nix ./programs/watson.nix + ./programs/waylogout.nix ./programs/waybar.nix ./programs/wezterm.nix ./programs/wlogout.nix ./programs/wofi.nix - ./programs/wpaperd.nix ./programs/xmobar.nix ./programs/xplr.nix ./programs/xonsh.nix @@ -302,10 +314,12 @@ let ./services/cliphist.nix ./services/clipman.nix ./services/clipmenu.nix + ./services/clipse.nix ./services/comodoro.nix ./services/conky.nix ./services/copyq.nix ./services/darkman.nix + ./services/davmail.nix ./services/devilspie2.nix ./services/dropbox.nix ./services/dunst.nix @@ -329,22 +343,28 @@ let ./services/hound.nix ./services/hypridle.nix ./services/hyprpaper.nix + ./services/hyprpolkitagent.nix ./services/imapnotify.nix + ./services/jankyborders.nix ./services/kanshi.nix ./services/kbfs.nix ./services/kdeconnect.nix ./services/keybase.nix ./services/keynav.nix + ./services/librespot.nix ./services/lieer.nix ./services/linux-wallpaperengine.nix ./services/listenbrainz-mpd.nix ./services/lorri.nix + ./services/lxqt-policykit-agent.nix + ./services/macos-remap-keys ./services/mako.nix ./services/mbsync.nix ./services/megasync.nix ./services/mopidy.nix ./services/mpd.nix ./services/mpdris2.nix + ./services/mpdscribble.nix ./services/mpd-discord-rpc.nix ./services/mpd-mpris.nix ./services/mpris-proxy.nix @@ -367,6 +387,7 @@ let ./services/playerctld.nix ./services/plex-mpv-shim.nix ./services/podman-linux + ./services/polkit-gnome.nix ./services/polybar.nix ./services/poweralertd.nix ./services/psd.nix @@ -382,6 +403,7 @@ let ./services/screen-locker.nix ./services/sctd.nix ./services/signaturepdf.nix + ./services/skhd.nix ./services/snixembed.nix ./services/spotifyd.nix ./services/ssh-agent.nix @@ -390,6 +412,7 @@ let ./services/swayidle.nix ./services/swaync.nix ./services/swayosd.nix + ./services/swww.nix ./services/sxhkd.nix ./services/syncthing.nix ./services/systembus-notify.nix @@ -418,7 +441,9 @@ let ./services/window-managers/wayfire.nix ./services/window-managers/xmonad.nix ./services/wlsunset.nix + ./services/wluma.nix ./services/wob.nix + ./services/wpaperd.nix ./services/xcape.nix ./services/xembed-sni-proxy.nix ./services/xidlehook.nix @@ -436,28 +461,28 @@ let (pkgs.path + "/nixos/modules/misc/assertions.nix") (pkgs.path + "/nixos/modules/misc/meta.nix") - (mkRemovedOptionModule [ "services" "password-store-sync" ] '' + (lib.mkRemovedOptionModule [ "services" "password-store-sync" ] '' Use services.git-sync instead. '') - (mkRemovedOptionModule [ "services" "keepassx" ] '' + (lib.mkRemovedOptionModule [ "services" "keepassx" ] '' KeePassX is no longer maintained. '') - ] ++ optional useNixpkgsModule ./misc/nixpkgs.nix - ++ optional (!useNixpkgsModule) ./misc/nixpkgs-disabled.nix; + ] ++ lib.optional useNixpkgsModule ./misc/nixpkgs.nix + ++ lib.optional (!useNixpkgsModule) ./misc/nixpkgs-disabled.nix; pkgsModule = { config, ... }: { config = { _module.args.baseModules = modules; _module.args.pkgsPath = lib.mkDefault - (if versionAtLeast config.home.stateVersion "20.09" then + (if lib.versionAtLeast config.home.stateVersion "20.09" then pkgs.path else ); _module.args.pkgs = lib.mkDefault pkgs; _module.check = check; lib = lib.hm; - } // optionalAttrs useNixpkgsModule { - nixpkgs.system = mkDefault pkgs.stdenv.hostPlatform.system; + } // lib.optionalAttrs useNixpkgsModule { + nixpkgs.system = lib.mkDefault pkgs.stdenv.hostPlatform.system; }; }; diff --git a/modules/po/ca.po b/modules/po/ca.po index 80021463c..fde4fece4 100644 --- a/modules/po/ca.po +++ b/modules/po/ca.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: Home Manager Modules\n" "Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n" "POT-Creation-Date: 2025-01-03 09:09+0100\n" -"PO-Revision-Date: 2023-12-10 15:58+0000\n" -"Last-Translator: Nara Díaz Viñolas \n" +"PO-Revision-Date: 2025-02-19 21:00+0000\n" +"Last-Translator: Alejandro Masó Bonilla \n" "Language-Team: Catalan \n" "Language: ca\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.3-dev\n" +"X-Generator: Weblate 5.10.1-dev\n" #: modules/files.nix:188 msgid "Creating home file links in %s" @@ -29,11 +29,11 @@ msgstr "Netejant enllaços orfes de %s" #: modules/home-environment.nix:591 msgid "Creating new profile generation" -msgstr "" +msgstr "Creant una nova generació per al nou perfil" #: modules/home-environment.nix:594 msgid "No change so reusing latest profile generation" -msgstr "" +msgstr "No hi ha canvis llavors s'utilitzarà la generació anterior" #: modules/home-environment.nix:643 msgid "" @@ -55,13 +55,13 @@ msgstr "" "Potser hi ha un conflicte amb un paquet instal·lat mitjançant\n" "\"%s\"? Prova d'executar\n" "\n" -" %s\n" +". . . . %s\n" "\n" "i si hi ha un paquet conflictiu el pots eliminar amb\n" "\n" -" %s\n" +". . . . %s\n" "\n" -"i després provar d'activar la teva configuració de Home Manager de nou." +"Després provar d'activar la teva configuració de Home Manager de nou." #: modules/home-environment.nix:676 msgid "Activating %s" @@ -86,7 +86,7 @@ msgstr "Error: HOME està configurat a \"%s\", però s'esperava \"%s\"" #: modules/lib-bash/activation-init.sh:132 msgid "Starting Home Manager activation" -msgstr "Començant activació de Home Manager" +msgstr "Començant l'activació de Home Manager" #: modules/lib-bash/activation-init.sh:136 msgid "Sanity checking Nix" @@ -102,7 +102,7 @@ msgstr "Execució en viu" #: modules/lib-bash/activation-init.sh:159 msgid "Using Nix version: %s" -msgstr "Utilitzant versió de Nix: %s" +msgstr "Utilitzant la versió de Nix: %s" #: modules/lib-bash/activation-init.sh:162 msgid "Activation variables:" diff --git a/modules/po/zh_Hant.po b/modules/po/zh_Hant.po index 7c8e14619..dab8fd3c8 100644 --- a/modules/po/zh_Hant.po +++ b/modules/po/zh_Hant.po @@ -8,16 +8,16 @@ msgstr "" "Project-Id-Version: Home Manager Modules\n" "Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n" "POT-Creation-Date: 2025-01-03 09:09+0100\n" -"PO-Revision-Date: 2023-01-08 11:50+0000\n" -"Last-Translator: Eric Ho \n" -"Language-Team: Chinese (Traditional) \n" +"PO-Revision-Date: 2025-03-07 18:58+0000\n" +"Last-Translator: 807 \n" +"Language-Team: Chinese (Traditional Han script) \n" "Language: zh_Hant\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.15.1-dev\n" +"X-Generator: Weblate 5.10.3-dev\n" #: modules/files.nix:188 msgid "Creating home file links in %s" @@ -29,11 +29,11 @@ msgstr "正在從 %s 清理孤立連結" #: modules/home-environment.nix:591 msgid "Creating new profile generation" -msgstr "" +msgstr "正在建立新一代的配置文件中" #: modules/home-environment.nix:594 msgid "No change so reusing latest profile generation" -msgstr "" +msgstr "為發生改變,請重新使用新一代的配置文件" #: modules/home-environment.nix:643 msgid "" @@ -69,19 +69,19 @@ msgstr "正在啟用 %s" #: modules/lib-bash/activation-init.sh:22 msgid "Migrating profile from %s to %s" -msgstr "" +msgstr "正在從 %S 配置文件轉移到 %s 中" #: modules/lib-bash/activation-init.sh:54 msgid "Could not find suitable profile directory, tried %s and %s" -msgstr "" +msgstr "找不到合適的 profile 目錄,已經嘗試 %s 和 %s" #: modules/lib-bash/activation-init.sh:106 msgid "Error: USER is set to \"%s\" but we expect \"%s\"" -msgstr "" +msgstr "錯誤:USER 被設定為 「%s」但我們希望是 「%s」" #: modules/lib-bash/activation-init.sh:115 msgid "Error: HOME is set to \"%s\" but we expect \"%s\"" -msgstr "" +msgstr "錯誤:HOME 被設定為 「%s」但我們預期得到 「%s」" #: modules/lib-bash/activation-init.sh:132 msgid "Starting Home Manager activation" diff --git a/modules/programs/aerc-accounts.nix b/modules/programs/aerc-accounts.nix index 04f0165a0..8ebfef0bb 100644 --- a/modules/programs/aerc-accounts.nix +++ b/modules/programs/aerc-accounts.nix @@ -134,8 +134,9 @@ in { oauthParams = { auth, params }: if useOauth auth && params != null && params != { } then - "?" + builtins.concatStringsSep "&" lib.attrsets.mapAttrsToList - (k: v: k + "=" + lib.strings.escapeURL v) params + "?" + builtins.concatStringsSep "&" + (lib.attrsets.mapAttrsToList (k: v: k + "=" + lib.strings.escapeURL v) + (lib.attrsets.filterAttrs (k: v: v != null) params)) else ""; diff --git a/modules/programs/aerc.nix b/modules/programs/aerc.nix index 7a48d91a5..477bfddfd 100644 --- a/modules/programs/aerc.nix +++ b/modules/programs/aerc.nix @@ -38,7 +38,7 @@ in { enable = mkEnableOption "aerc"; - package = mkPackageOption pkgs "aerc" { }; + package = mkPackageOption pkgs "aerc" { nullable = true; }; extraAccounts = mkOption { type = sectionsOrLines; @@ -193,7 +193,7 @@ in { ''; }]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file = { "${configDir}/accounts.conf" = mkIf genAccountsConf { diff --git a/modules/programs/aerospace.nix b/modules/programs/aerospace.nix index 62f33752f..bb66fee4d 100644 --- a/modules/programs/aerospace.nix +++ b/modules/programs/aerospace.nix @@ -29,7 +29,7 @@ in { options.programs.aerospace = { enable = lib.mkEnableOption "AeroSpace window manager"; - package = lib.mkPackageOption pkgs "aerospace" { }; + package = lib.mkPackageOption pkgs "aerospace" { nullable = true; }; userSettings = mkOption { type = types.submodule { @@ -232,7 +232,7 @@ in { ]; home = { - packages = [ cfg.package ]; + packages = lib.mkIf (cfg.package != null) [ cfg.package ]; file.".config/aerospace/aerospace.toml".source = tomlFormat.generate "aerospace" (filterNulls cfg.userSettings); }; diff --git a/modules/programs/alot.nix b/modules/programs/alot.nix index 10dec7c0c..243215746 100644 --- a/modules/programs/alot.nix +++ b/modules/programs/alot.nix @@ -132,7 +132,7 @@ in { ''; }; - package = mkPackageOption pkgs "alot" { }; + package = mkPackageOption pkgs "alot" { nullable = true; }; hooks = mkOption { type = types.lines; @@ -231,7 +231,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."alot/config".text = configFile; diff --git a/modules/programs/antidote.nix b/modules/programs/antidote.nix index 8db5a9a82..8cf3d5a48 100644 --- a/modules/programs/antidote.nix +++ b/modules/programs/antidote.nix @@ -31,12 +31,12 @@ in { config = mkIf cfg.enable { home.packages = [ cfg.package ]; - programs.zsh.initExtraBeforeCompInit = let + programs.zsh.initContent = let configFiles = pkgs.runCommand "hm_antidote-files" { } '' echo "${zPluginStr cfg.plugins}" > $out ''; hashId = parseHashId "${configFiles}"; - in '' + in (mkOrder 550 '' ## home-manager/antidote begin : source ${cfg.package}/share/antidote/antidote.zsh ${optionalString cfg.useFriendlyNames @@ -50,6 +50,6 @@ in { antidote load $bundlefile $staticfile ## home-manager/antidote end - ''; + ''); }; } diff --git a/modules/programs/atuin.nix b/modules/programs/atuin.nix index f708aed94..0e2be233f 100644 --- a/modules/programs/atuin.nix +++ b/modules/programs/atuin.nix @@ -124,7 +124,7 @@ in { fi ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' if [[ $options[zle] = on ]]; then eval "$(${lib.getExe cfg.package} init zsh ${flagsStr})" fi diff --git a/modules/programs/autojump.nix b/modules/programs/autojump.nix index 3177001c8..3d7f1ad95 100644 --- a/modules/programs/autojump.nix +++ b/modules/programs/autojump.nix @@ -30,7 +30,7 @@ in { . ${package}/share/autojump/autojump.bash ''); - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' . ${package}/share/autojump/autojump.zsh ''; diff --git a/modules/programs/bacon.nix b/modules/programs/bacon.nix index ad2e9b5b8..528be2a06 100644 --- a/modules/programs/bacon.nix +++ b/modules/programs/bacon.nix @@ -19,7 +19,7 @@ in { options.programs.bacon = { enable = mkEnableOption "bacon, a background rust code checker"; - package = mkPackageOption pkgs "bacon" { }; + package = mkPackageOption pkgs "bacon" { nullable = true; }; settings = mkOption { type = settingsFormat.type; @@ -38,7 +38,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file."${configDir}/prefs.toml" = mkIf (cfg.settings != { }) { source = settingsFormat.generate "prefs.toml" cfg.settings; diff --git a/modules/programs/bash.nix b/modules/programs/bash.nix index 0c99da3ed..e9cf983dd 100644 --- a/modules/programs/bash.nix +++ b/modules/programs/bash.nix @@ -29,7 +29,10 @@ in { programs.bash = { enable = mkEnableOption "GNU Bourne-Again SHell"; - package = mkPackageOption pkgs "bash" { default = "bashInteractive"; }; + package = mkPackageOption pkgs "bash" { + nullable = true; + default = "bashInteractive"; + }; enableCompletion = mkOption { type = types.bool; @@ -195,7 +198,7 @@ in { }) ++ optional (cfg.historyFile != null) ''mkdir -p "$(dirname "$HISTFILE")"'')); in mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file.".bash_profile".source = writeBashScript "bash_profile" '' # include .profile if it exists diff --git a/modules/programs/bemenu.nix b/modules/programs/bemenu.nix index f90067216..6c6e793ff 100644 --- a/modules/programs/bemenu.nix +++ b/modules/programs/bemenu.nix @@ -12,7 +12,7 @@ in { options.programs.bemenu = { enable = mkEnableOption "bemenu"; - package = mkPackageOption pkgs "bemenu" { }; + package = mkPackageOption pkgs "bemenu" { nullable = true; }; settings = mkOption { type = with types; attrsOf (oneOf [ str number bool ]); @@ -44,7 +44,7 @@ in { assertions = [ (hm.assertions.assertPlatform "programs.bemenu" pkgs platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.sessionVariables = mkIf (cfg.settings != { }) { BEMENU_OPTS = cli.toGNUCommandLineShell { } cfg.settings; diff --git a/modules/programs/borgmatic.nix b/modules/programs/borgmatic.nix index 97a1d54ce..92f171c27 100644 --- a/modules/programs/borgmatic.nix +++ b/modules/programs/borgmatic.nix @@ -243,7 +243,7 @@ in { programs.borgmatic = { enable = mkEnableOption "Borgmatic"; - package = mkPackageOption pkgs "borgmatic" { }; + package = mkPackageOption pkgs "borgmatic" { nullable = true; }; backups = mkOption { type = types.attrsOf configModule; @@ -292,6 +292,6 @@ in { text = writeConfig config; }) cfg.backups; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; }; } diff --git a/modules/programs/boxxy.nix b/modules/programs/boxxy.nix index 566a11e7e..dc6c1cbdc 100644 --- a/modules/programs/boxxy.nix +++ b/modules/programs/boxxy.nix @@ -84,7 +84,7 @@ in { options.programs.boxxy = { enable = mkEnableOption "boxxy: Boxes in badly behaving applications"; - package = mkPackageOption pkgs "boxxy" { }; + package = mkPackageOption pkgs "boxxy" { nullable = true; }; rules = mkOption { type = types.listOf boxxyRulesOpts; @@ -102,7 +102,7 @@ in { settingsFormat.generate "boxxy-config.yaml" { rules = cfg.rules; }; }; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; }; meta.maintainers = with lib.hm.maintainers; [ nikp123 ]; diff --git a/modules/programs/broot.nix b/modules/programs/broot.nix index c19534f1a..8cc6338c1 100644 --- a/modules/programs/broot.nix +++ b/modules/programs/broot.nix @@ -214,7 +214,7 @@ in { programs.bash.initExtra = mkIf cfg.enableBashIntegration (shellInit "bash"); - programs.zsh.initExtra = mkIf cfg.enableZshIntegration (shellInit "zsh"); + programs.zsh.initContent = mkIf cfg.enableZshIntegration (shellInit "zsh"); programs.fish.shellInit = mkIf cfg.enableFishIntegration (shellInit "fish"); diff --git a/modules/programs/btop.nix b/modules/programs/btop.nix index b05e78995..61c7f795a 100644 --- a/modules/programs/btop.nix +++ b/modules/programs/btop.nix @@ -25,7 +25,7 @@ in { options.programs.btop = { enable = lib.mkEnableOption "btop"; - package = lib.mkPackageOption pkgs "btop" { }; + package = lib.mkPackageOption pkgs "btop" { nullable = true; }; settings = lib.mkOption { type = with lib.types; attrsOf (oneOf [ bool float int str ]); @@ -51,7 +51,7 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."btop/btop.conf" = lib.mkIf (cfg.settings != { }) { text = finalConfig; }; diff --git a/modules/programs/bun.nix b/modules/programs/bun.nix index f186982e2..ffc9167ef 100644 --- a/modules/programs/bun.nix +++ b/modules/programs/bun.nix @@ -9,7 +9,7 @@ in { options.programs.bun = { enable = lib.mkEnableOption "Bun JavaScript runtime"; - package = lib.mkPackageOption pkgs "bun" { }; + package = lib.mkPackageOption pkgs "bun" { nullable = true; }; settings = lib.mkOption { type = tomlFormat.type; @@ -42,7 +42,13 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [ cfg.package ]; + warnings = lib.optional (cfg.package == null && cfg.enableGitIntegration) '' + You have enabled git integration for `bun` but have not set `package`. + + Git integration will not be configured. + ''; + + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile.".bunfig.toml" = lib.mkIf (cfg.settings != { }) { source = tomlFormat.generate "bun-config" cfg.settings; @@ -50,10 +56,12 @@ in { # https://bun.sh/docs/install/lockfile#how-do-i-git-diff-bun-s-lockfile programs.git.attributes = - lib.mkIf cfg.enableGitIntegration [ "*.lockb binary diff=lockb" ]; - programs.git.extraConfig.diff.lockb = lib.mkIf cfg.enableGitIntegration { - textconv = lib.getExe cfg.package; - binary = true; - }; + lib.mkIf (cfg.enableGitIntegration && (cfg.package != null)) + [ "*.lockb binary diff=lockb" ]; + programs.git.extraConfig.diff.lockb = + lib.mkIf (cfg.enableGitIntegration && (cfg.package != null)) { + textconv = lib.getExe cfg.package; + binary = true; + }; }; } diff --git a/modules/programs/carapace.nix b/modules/programs/carapace.nix index 5dcefc522..f70d40bc5 100644 --- a/modules/programs/carapace.nix +++ b/modules/programs/carapace.nix @@ -41,7 +41,7 @@ in { source <(${bin} _carapace bash) ''; - zsh.initExtra = mkIf cfg.enableZshIntegration '' + zsh.initContent = mkIf cfg.enableZshIntegration '' source <(${bin} _carapace zsh) ''; @@ -69,18 +69,23 @@ in { }; }; - xdg.configFile = - mkIf (config.programs.fish.enable && cfg.enableFishIntegration) ( + xdg.configFile = mkIf (config.programs.fish.enable + && cfg.enableFishIntegration + && lib.versionOlder config.programs.fish.package.version "4.0.0") ( # Convert the entries from `carapace --list` to empty # xdg.configFile."fish/completions/NAME.fish" entries. # # This is to disable fish builtin completion for each of the - # carapace-supported completions It is in line with the instructions from + # carapace-supported completions. + # + # This is necessary for carapace to properly work with fish version < 4.0b1. + # + # It is in line with the instructions from # carapace-bin: # # carapace --list | awk '{print $1}' | xargs -I{} touch ~/.config/fish/completions/{}.fish # - # See https://github.com/rsteube/carapace-bin#getting-started + # See https://carapace-sh.github.io/carapace-bin/setup.html#fish let carapaceListFile = pkgs.runCommandLocal "carapace-list" { buildInputs = [ cfg.package ]; diff --git a/modules/programs/cava.nix b/modules/programs/cava.nix index 63173248f..946656b06 100644 --- a/modules/programs/cava.nix +++ b/modules/programs/cava.nix @@ -14,7 +14,7 @@ in { options.programs.cava = { enable = mkEnableOption "Cava audio visualizer"; - package = mkPackageOption pkgs "cava" { }; + package = mkPackageOption pkgs "cava" { nullable = true; }; settings = mkOption { type = iniFmt.type; @@ -39,7 +39,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."cava/config" = mkIf (cfg.settings != { }) { text = '' diff --git a/modules/programs/cavalier.nix b/modules/programs/cavalier.nix index 0b57cf8e2..8ba05de93 100644 --- a/modules/programs/cavalier.nix +++ b/modules/programs/cavalier.nix @@ -16,7 +16,7 @@ in { options.programs.cavalier = { enable = mkEnableOption "Cava audio visualizer GUI"; - package = mkPackageOption pkgs "cavalier" { }; + package = mkPackageOption pkgs "cavalier" { nullable = true; }; settings = { general = mkOption { @@ -81,7 +81,7 @@ in { lib.platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile = { "Nickvision Cavalier/config.json" = mkIf (cfg.settings.general != { }) { diff --git a/modules/programs/chromium.nix b/modules/programs/chromium.nix index 0a02311b7..ffb488fc9 100644 --- a/modules/programs/chromium.nix +++ b/modules/programs/chromium.nix @@ -137,6 +137,18 @@ let List of ${name} dictionaries to install. ''; }; + nativeMessagingHosts = mkOption { + type = types.listOf types.package; + default = [ ]; + example = literalExpression '' + [ + pkgs.kdePackages.plasma-browser-integration + ] + ''; + description = '' + List of ${name} native messaging hosts to install. + ''; + }; }; browserConfig = cfg: @@ -178,6 +190,11 @@ let value.source = pkg; }; + nativeMessagingHostsJoined = pkgs.symlinkJoin { + name = "${drvName}-native-messaging-hosts"; + paths = cfg.nativeMessagingHosts; + }; + package = if cfg.commandLineArgs != [ ] then cfg.package.override { commandLineArgs = concatStringsSep " " cfg.commandLineArgs; @@ -189,7 +206,14 @@ let home.packages = [ package ]; home.file = optionalAttrs (!isProprietaryChrome) (listToAttrs ((map extensionJson cfg.extensions) - ++ (map dictionary cfg.dictionaries))); + ++ (map dictionary cfg.dictionaries)) // { + "${configDir}/NativeMessagingHosts" = + lib.mkIf (cfg.nativeMessagingHosts != [ ]) { + source = + "${nativeMessagingHostsJoined}/etc/chromium/native-messaging-hosts"; + recursive = true; + }; + }); }; in { diff --git a/modules/programs/comodoro.nix b/modules/programs/comodoro.nix index fba0bce86..af59261ef 100644 --- a/modules/programs/comodoro.nix +++ b/modules/programs/comodoro.nix @@ -10,7 +10,7 @@ in { options.programs.comodoro = { enable = lib.mkEnableOption "Comodoro, a CLI to manage your time"; - package = lib.mkPackageOption pkgs "comodoro" { }; + package = lib.mkPackageOption pkgs "comodoro" { nullable = true; }; settings = lib.mkOption { type = lib.types.submodule { freeformType = tomlFormat.type; }; @@ -23,7 +23,7 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."comodoro/config.toml".source = tomlFormat.generate "comodoro-config.toml" cfg.settings; diff --git a/modules/programs/darcs.nix b/modules/programs/darcs.nix index a2a45cba4..263d668fe 100644 --- a/modules/programs/darcs.nix +++ b/modules/programs/darcs.nix @@ -13,7 +13,7 @@ in { programs.darcs = { enable = mkEnableOption "darcs"; - package = mkPackageOption pkgs "darcs" { }; + package = mkPackageOption pkgs "darcs" { nullable = true; }; author = mkOption { type = types.listOf types.str; @@ -36,7 +36,7 @@ in { }; config = mkIf cfg.enable (mkMerge [ - { home.packages = [ cfg.package ]; } + { home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; } (mkIf (cfg.author != [ ]) { home.file.".darcs/author".text = diff --git a/modules/programs/dircolors.nix b/modules/programs/dircolors.nix index 91aaff41f..85c1b4333 100644 --- a/modules/programs/dircolors.nix +++ b/modules/programs/dircolors.nix @@ -54,155 +54,168 @@ in { }; }; - config = mkIf cfg.enable { - # Add default settings from `dircolors --print-database`. - programs.dircolors.settings = { - RESET = mkDefault "0"; - DIR = mkDefault "01;34"; - LINK = mkDefault "01;36"; - MULTIHARDLINK = mkDefault "00"; - FIFO = mkDefault "40;33"; - SOCK = mkDefault "01;35"; - DOOR = mkDefault "01;35"; - BLK = mkDefault "40;33;01"; - CHR = mkDefault "40;33;01"; - ORPHAN = mkDefault "40;31;01"; - MISSING = mkDefault "00"; - SETUID = mkDefault "37;41"; - SETGID = mkDefault "30;43"; - CAPABILITY = mkDefault "30;41"; - STICKY_OTHER_WRITABLE = mkDefault "30;42"; - OTHER_WRITABLE = mkDefault "34;42"; - STICKY = mkDefault "37;44"; - EXEC = mkDefault "01;32"; - ".tar" = mkDefault "01;31"; - ".tgz" = mkDefault "01;31"; - ".arc" = mkDefault "01;31"; - ".arj" = mkDefault "01;31"; - ".taz" = mkDefault "01;31"; - ".lha" = mkDefault "01;31"; - ".lz4" = mkDefault "01;31"; - ".lzh" = mkDefault "01;31"; - ".lzma" = mkDefault "01;31"; - ".tlz" = mkDefault "01;31"; - ".txz" = mkDefault "01;31"; - ".tzo" = mkDefault "01;31"; - ".t7z" = mkDefault "01;31"; - ".zip" = mkDefault "01;31"; - ".z" = mkDefault "01;31"; - ".dz" = mkDefault "01;31"; - ".gz" = mkDefault "01;31"; - ".lrz" = mkDefault "01;31"; - ".lz" = mkDefault "01;31"; - ".lzo" = mkDefault "01;31"; - ".xz" = mkDefault "01;31"; - ".zst" = mkDefault "01;31"; - ".tzst" = mkDefault "01;31"; - ".bz2" = mkDefault "01;31"; - ".bz" = mkDefault "01;31"; - ".tbz" = mkDefault "01;31"; - ".tbz2" = mkDefault "01;31"; - ".tz" = mkDefault "01;31"; - ".deb" = mkDefault "01;31"; - ".rpm" = mkDefault "01;31"; - ".jar" = mkDefault "01;31"; - ".war" = mkDefault "01;31"; - ".ear" = mkDefault "01;31"; - ".sar" = mkDefault "01;31"; - ".rar" = mkDefault "01;31"; - ".alz" = mkDefault "01;31"; - ".ace" = mkDefault "01;31"; - ".zoo" = mkDefault "01;31"; - ".cpio" = mkDefault "01;31"; - ".7z" = mkDefault "01;31"; - ".rz" = mkDefault "01;31"; - ".cab" = mkDefault "01;31"; - ".wim" = mkDefault "01;31"; - ".swm" = mkDefault "01;31"; - ".dwm" = mkDefault "01;31"; - ".esd" = mkDefault "01;31"; - ".jpg" = mkDefault "01;35"; - ".jpeg" = mkDefault "01;35"; - ".mjpg" = mkDefault "01;35"; - ".mjpeg" = mkDefault "01;35"; - ".gif" = mkDefault "01;35"; - ".bmp" = mkDefault "01;35"; - ".pbm" = mkDefault "01;35"; - ".pgm" = mkDefault "01;35"; - ".ppm" = mkDefault "01;35"; - ".tga" = mkDefault "01;35"; - ".xbm" = mkDefault "01;35"; - ".xpm" = mkDefault "01;35"; - ".tif" = mkDefault "01;35"; - ".tiff" = mkDefault "01;35"; - ".png" = mkDefault "01;35"; - ".svg" = mkDefault "01;35"; - ".svgz" = mkDefault "01;35"; - ".mng" = mkDefault "01;35"; - ".pcx" = mkDefault "01;35"; - ".mov" = mkDefault "01;35"; - ".mpg" = mkDefault "01;35"; - ".mpeg" = mkDefault "01;35"; - ".m2v" = mkDefault "01;35"; - ".mkv" = mkDefault "01;35"; - ".webm" = mkDefault "01;35"; - ".ogm" = mkDefault "01;35"; - ".mp4" = mkDefault "01;35"; - ".m4v" = mkDefault "01;35"; - ".mp4v" = mkDefault "01;35"; - ".vob" = mkDefault "01;35"; - ".qt" = mkDefault "01;35"; - ".nuv" = mkDefault "01;35"; - ".wmv" = mkDefault "01;35"; - ".asf" = mkDefault "01;35"; - ".rm" = mkDefault "01;35"; - ".rmvb" = mkDefault "01;35"; - ".flc" = mkDefault "01;35"; - ".avi" = mkDefault "01;35"; - ".fli" = mkDefault "01;35"; - ".flv" = mkDefault "01;35"; - ".gl" = mkDefault "01;35"; - ".dl" = mkDefault "01;35"; - ".xcf" = mkDefault "01;35"; - ".xwd" = mkDefault "01;35"; - ".yuv" = mkDefault "01;35"; - ".cgm" = mkDefault "01;35"; - ".emf" = mkDefault "01;35"; - ".ogv" = mkDefault "01;35"; - ".ogx" = mkDefault "01;35"; - ".aac" = mkDefault "00;36"; - ".au" = mkDefault "00;36"; - ".flac" = mkDefault "00;36"; - ".m4a" = mkDefault "00;36"; - ".mid" = mkDefault "00;36"; - ".midi" = mkDefault "00;36"; - ".mka" = mkDefault "00;36"; - ".mp3" = mkDefault "00;36"; - ".mpc" = mkDefault "00;36"; - ".ogg" = mkDefault "00;36"; - ".ra" = mkDefault "00;36"; - ".wav" = mkDefault "00;36"; - ".oga" = mkDefault "00;36"; - ".opus" = mkDefault "00;36"; - ".spx" = mkDefault "00;36"; - ".xspf" = mkDefault "00;36"; - }; + config = let + dircolorsPath = if config.home.preferXdgDirectories then + "${config.xdg.configHome}/dir_colors" + else + "~/.dir_colors"; - home.file.".dir_colors".text = concatStringsSep "\n" ([ ] + dircolorsConfig = concatStringsSep "\n" ([ ] ++ mapAttrsToList formatLine cfg.settings ++ [ "" ] ++ optional (cfg.extraConfig != "") cfg.extraConfig); + in mkIf cfg.enable (mkMerge [ + { + # Add default settings from `dircolors --print-database`. + programs.dircolors.settings = { + RESET = mkDefault "0"; + DIR = mkDefault "01;34"; + LINK = mkDefault "01;36"; + MULTIHARDLINK = mkDefault "00"; + FIFO = mkDefault "40;33"; + SOCK = mkDefault "01;35"; + DOOR = mkDefault "01;35"; + BLK = mkDefault "40;33;01"; + CHR = mkDefault "40;33;01"; + ORPHAN = mkDefault "40;31;01"; + MISSING = mkDefault "00"; + SETUID = mkDefault "37;41"; + SETGID = mkDefault "30;43"; + CAPABILITY = mkDefault "30;41"; + STICKY_OTHER_WRITABLE = mkDefault "30;42"; + OTHER_WRITABLE = mkDefault "34;42"; + STICKY = mkDefault "37;44"; + EXEC = mkDefault "01;32"; + ".tar" = mkDefault "01;31"; + ".tgz" = mkDefault "01;31"; + ".arc" = mkDefault "01;31"; + ".arj" = mkDefault "01;31"; + ".taz" = mkDefault "01;31"; + ".lha" = mkDefault "01;31"; + ".lz4" = mkDefault "01;31"; + ".lzh" = mkDefault "01;31"; + ".lzma" = mkDefault "01;31"; + ".tlz" = mkDefault "01;31"; + ".txz" = mkDefault "01;31"; + ".tzo" = mkDefault "01;31"; + ".t7z" = mkDefault "01;31"; + ".zip" = mkDefault "01;31"; + ".z" = mkDefault "01;31"; + ".dz" = mkDefault "01;31"; + ".gz" = mkDefault "01;31"; + ".lrz" = mkDefault "01;31"; + ".lz" = mkDefault "01;31"; + ".lzo" = mkDefault "01;31"; + ".xz" = mkDefault "01;31"; + ".zst" = mkDefault "01;31"; + ".tzst" = mkDefault "01;31"; + ".bz2" = mkDefault "01;31"; + ".bz" = mkDefault "01;31"; + ".tbz" = mkDefault "01;31"; + ".tbz2" = mkDefault "01;31"; + ".tz" = mkDefault "01;31"; + ".deb" = mkDefault "01;31"; + ".rpm" = mkDefault "01;31"; + ".jar" = mkDefault "01;31"; + ".war" = mkDefault "01;31"; + ".ear" = mkDefault "01;31"; + ".sar" = mkDefault "01;31"; + ".rar" = mkDefault "01;31"; + ".alz" = mkDefault "01;31"; + ".ace" = mkDefault "01;31"; + ".zoo" = mkDefault "01;31"; + ".cpio" = mkDefault "01;31"; + ".7z" = mkDefault "01;31"; + ".rz" = mkDefault "01;31"; + ".cab" = mkDefault "01;31"; + ".wim" = mkDefault "01;31"; + ".swm" = mkDefault "01;31"; + ".dwm" = mkDefault "01;31"; + ".esd" = mkDefault "01;31"; + ".jpg" = mkDefault "01;35"; + ".jpeg" = mkDefault "01;35"; + ".mjpg" = mkDefault "01;35"; + ".mjpeg" = mkDefault "01;35"; + ".gif" = mkDefault "01;35"; + ".bmp" = mkDefault "01;35"; + ".pbm" = mkDefault "01;35"; + ".pgm" = mkDefault "01;35"; + ".ppm" = mkDefault "01;35"; + ".tga" = mkDefault "01;35"; + ".xbm" = mkDefault "01;35"; + ".xpm" = mkDefault "01;35"; + ".tif" = mkDefault "01;35"; + ".tiff" = mkDefault "01;35"; + ".png" = mkDefault "01;35"; + ".svg" = mkDefault "01;35"; + ".svgz" = mkDefault "01;35"; + ".mng" = mkDefault "01;35"; + ".pcx" = mkDefault "01;35"; + ".mov" = mkDefault "01;35"; + ".mpg" = mkDefault "01;35"; + ".mpeg" = mkDefault "01;35"; + ".m2v" = mkDefault "01;35"; + ".mkv" = mkDefault "01;35"; + ".webm" = mkDefault "01;35"; + ".ogm" = mkDefault "01;35"; + ".mp4" = mkDefault "01;35"; + ".m4v" = mkDefault "01;35"; + ".mp4v" = mkDefault "01;35"; + ".vob" = mkDefault "01;35"; + ".qt" = mkDefault "01;35"; + ".nuv" = mkDefault "01;35"; + ".wmv" = mkDefault "01;35"; + ".asf" = mkDefault "01;35"; + ".rm" = mkDefault "01;35"; + ".rmvb" = mkDefault "01;35"; + ".flc" = mkDefault "01;35"; + ".avi" = mkDefault "01;35"; + ".fli" = mkDefault "01;35"; + ".flv" = mkDefault "01;35"; + ".gl" = mkDefault "01;35"; + ".dl" = mkDefault "01;35"; + ".xcf" = mkDefault "01;35"; + ".xwd" = mkDefault "01;35"; + ".yuv" = mkDefault "01;35"; + ".cgm" = mkDefault "01;35"; + ".emf" = mkDefault "01;35"; + ".ogv" = mkDefault "01;35"; + ".ogx" = mkDefault "01;35"; + ".aac" = mkDefault "00;36"; + ".au" = mkDefault "00;36"; + ".flac" = mkDefault "00;36"; + ".m4a" = mkDefault "00;36"; + ".mid" = mkDefault "00;36"; + ".midi" = mkDefault "00;36"; + ".mka" = mkDefault "00;36"; + ".mp3" = mkDefault "00;36"; + ".mpc" = mkDefault "00;36"; + ".ogg" = mkDefault "00;36"; + ".ra" = mkDefault "00;36"; + ".wav" = mkDefault "00;36"; + ".oga" = mkDefault "00;36"; + ".opus" = mkDefault "00;36"; + ".spx" = mkDefault "00;36"; + ".xspf" = mkDefault "00;36"; + }; - programs.bash.initExtra = mkIf cfg.enableBashIntegration '' - eval $(${pkgs.coreutils}/bin/dircolors -b ~/.dir_colors) - ''; + programs.bash.initExtra = mkIf cfg.enableBashIntegration '' + eval $(${pkgs.coreutils}/bin/dircolors -b ${dircolorsPath}) + ''; - programs.fish.shellInit = mkIf cfg.enableFishIntegration '' - eval (${pkgs.coreutils}/bin/dircolors -c ~/.dir_colors) - ''; + programs.fish.shellInit = mkIf cfg.enableFishIntegration '' + eval (${pkgs.coreutils}/bin/dircolors -c ${dircolorsPath}) + ''; - # Set `LS_COLORS` before Oh My Zsh and `initExtra`. - programs.zsh.initExtraBeforeCompInit = mkIf cfg.enableZshIntegration '' - eval $(${pkgs.coreutils}/bin/dircolors -b ~/.dir_colors) - ''; - }; + # Set `LS_COLORS` before Oh My Zsh and `initExtra`. + programs.zsh.initContent = mkIf cfg.enableZshIntegration (mkOrder 550 '' + eval $(${pkgs.coreutils}/bin/dircolors -b ${dircolorsPath}) + ''); + } + (mkIf (!config.home.preferXdgDirectories) { + home.file.".dir_colors".text = dircolorsConfig; + }) + (mkIf config.home.preferXdgDirectories { + xdg.configFile.dir_colors.text = dircolorsConfig; + }) + ]); } diff --git a/modules/programs/direnv.nix b/modules/programs/direnv.nix index 7ec95cd97..e75ced800 100644 --- a/modules/programs/direnv.nix +++ b/modules/programs/direnv.nix @@ -54,7 +54,7 @@ in { enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { inherit config; extraDescription = '' - Note, enabling the direnv module will always active its functionality + Note, enabling the direnv module will always activate its functionality for Fish since the direnv package automatically gets loaded in Fish. If this is not the case try adding ```nix @@ -128,7 +128,7 @@ in { eval "$(${getExe cfg.package} hook bash)" ''); - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' eval "$(${getExe cfg.package} hook zsh)" ''; diff --git a/modules/programs/discocss.nix b/modules/programs/discocss.nix index 5a35f187f..7fa2c7965 100644 --- a/modules/programs/discocss.nix +++ b/modules/programs/discocss.nix @@ -11,9 +11,9 @@ in { enable = mkEnableOption "discocss, a tiny Discord CSS injector for Linux and MacOS"; - package = mkPackageOption pkgs "discocss" { }; + package = mkPackageOption pkgs "discocss" { nullable = true; }; - discordPackage = mkPackageOption pkgs "discord" { }; + discordPackage = mkPackageOption pkgs "discord" { nullable = true; }; discordAlias = mkOption { type = types.bool; @@ -37,10 +37,10 @@ in { "To use discocss with discordAlias you have to remove discord from home.packages, or set discordAlias to false."; }]; - home.packages = [ + home.packages = lib.mkIf (cfg.package != null) [ (cfg.package.override { discordAlias = cfg.discordAlias; - discord = cfg.discordPackage; + discord = lib.mkIf (cfg.discordPackage != null) cfg.discordPackage; }) ]; diff --git a/modules/programs/distrobox.nix b/modules/programs/distrobox.nix new file mode 100644 index 000000000..30e716644 --- /dev/null +++ b/modules/programs/distrobox.nix @@ -0,0 +1,96 @@ +{ lib, pkgs, config, ... }: +let + inherit (lib) generators types mkIf mkEnableOption mkPackageOption mkOption; + + cfg = config.programs.distrobox; + + formatter = pkgs.formats.ini { listsAsDuplicateKeys = true; }; +in { + meta.maintainers = with lib.hm.maintainers; [ aguirre-matteo ]; + + options.programs.distrobox = { + enable = mkEnableOption "distrobox"; + + package = mkPackageOption pkgs "distrobox" { }; + + containers = mkOption { + type = formatter.type; + default = { }; + example = '' + { + python-project = { + image = "fedora:40"; + additional_packages = "python3 git"; + init_hooks = "pip3 install numpy pandas torch torchvision"; + }; + + common-debian = { + image = "debian:13"; + entry = true; + additional_packages = "git"; + init_hooks = [ + "ln -sf /usr/bin/distrobox-host-exec /usr/local/bin/docker" + "ln -sf /usr/bin/distrobox-host-exec /usr/local/bin/docker-compose" + ]; + }; + + office = { + clone = "common-debian"; + additional_packages = "libreoffice onlyoffice"; + entry = true; + }; + + random-things = { + clone = "common-debian"; + entry = false; + }; + } + ''; + description = '' + A set of containers and all its respective configurations. Each option can be either a + bool, string or a list of strings. If passed a list, the option will be repeated for each element. + See common-debian in the example config. All the available options for the containers can be found + in the distrobox-assemble documentation at . + ''; + }; + }; + + config = mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "programs.distrobox" pkgs + lib.platforms.linux) + ]; + + home.packages = [ cfg.package ]; + + xdg.configFile."distrobox/containers.ini".source = + (formatter.generate "containers.ini" cfg.containers); + + systemd.user.services.distrobox-home-manager = { + Unit.Description = + "Build the containers declared in ~/.config/distrobox/containers.ini"; + Install.WantedBy = [ "default.target" ]; + + Service.ExecStart = "${pkgs.writeShellScript "distrobox-home-manager" '' + PATH=/run/current-system/sw/bin: + + containers_file=${config.xdg.configHome}/distrobox/containers.ini + prev_hash_file=${config.xdg.configHome}/distrobox/prev_hash + new_hash=$(sha256sum $containers_file | cut -f 1 -d " ") + + if [[ -f $prev_hash_file ]]; then + prev_hash=$(cat $prev_hash_file) + else + prev_hash=0 + fi + + if [[ $prev_hash != $new_hash ]]; then + rm -rf /tmp/storage-run-1000/containers + rm -rf /tmp/storage-run-1000/libpod/tmp + ${cfg.package}/bin/distrobox-assemble create --file $containers_file + echo $new_hash > $prev_hash_file + fi + ''}"; + }; + }; +} diff --git a/modules/programs/earthly.nix b/modules/programs/earthly.nix new file mode 100644 index 000000000..a2b2a44c1 --- /dev/null +++ b/modules/programs/earthly.nix @@ -0,0 +1,40 @@ +{ config, lib, pkgs, ... }: + +let + + cfg = config.programs.earthly; + + yamlFormat = pkgs.formats.yaml { }; + +in { + meta.maintainers = [ lib.hm.maintainers.folliehiyuki ]; + + options.programs.earthly = { + enable = lib.mkEnableOption "earthly"; + + package = lib.mkPackageOption pkgs "earthly" { nullable = true; }; + + settings = lib.mkOption { + type = yamlFormat.type; + default = { }; + description = '' + Configuration written to ~/.earthly/config.yml file. + See https://docs.earthly.dev/docs/earthly-config for supported values. + ''; + example = lib.literalExpression '' + global = { + disable_analytics = true; + disable_log_sharing = true; + }; + ''; + }; + }; + + config = lib.mkIf cfg.enable { + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + + home.file.".earthly/config.yml" = lib.mkIf (cfg.settings != { }) { + source = yamlFormat.generate "earthly-config" cfg.settings; + }; + }; +} diff --git a/modules/programs/eww.nix b/modules/programs/eww.nix index 2559068ad..2f59a50c6 100644 --- a/modules/programs/eww.nix +++ b/modules/programs/eww.nix @@ -54,7 +54,7 @@ in { fi ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' if [[ $TERM != "dumb" ]]; then eval "$(${ewwCmd} shell-completions --shell zsh)" fi diff --git a/modules/programs/eza.nix b/modules/programs/eza.nix index 0d18e1dc6..d51f1de96 100644 --- a/modules/programs/eza.nix +++ b/modules/programs/eza.nix @@ -75,7 +75,7 @@ with lib; ''; }; - package = mkPackageOption pkgs "eza" { }; + package = mkPackageOption pkgs "eza" { nullable = true; }; }; config = let @@ -108,7 +108,7 @@ with lib; programs.eza.icons = ${if cfg.icons then ''"auto"'' else "null"}''; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; programs.bash.shellAliases = optionsAlias // optionalAttrs cfg.enableBashIntegration aliases; diff --git a/modules/programs/fastfetch.nix b/modules/programs/fastfetch.nix index 246e200f4..abc4d7cda 100644 --- a/modules/programs/fastfetch.nix +++ b/modules/programs/fastfetch.nix @@ -13,7 +13,7 @@ in { options.programs.fastfetch = { enable = mkEnableOption "Fastfetch"; - package = mkPackageOption pkgs "fastfetch" { }; + package = mkPackageOption pkgs "fastfetch" { nullable = true; }; settings = mkOption { type = jsonFormat.type; @@ -59,7 +59,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."fastfetch/config.jsonc" = mkIf (cfg.settings != { }) { source = jsonFormat.generate "config.jsonc" cfg.settings; diff --git a/modules/programs/fd.nix b/modules/programs/fd.nix index f8f59eb54..17911ebed 100644 --- a/modules/programs/fd.nix +++ b/modules/programs/fd.nix @@ -30,7 +30,7 @@ with lib; { ''; }; - package = mkPackageOption pkgs "fd" { }; + package = mkPackageOption pkgs "fd" { nullable = true; }; }; config = let @@ -40,7 +40,7 @@ with lib; { optionsAlias = optionalAttrs (args != "") { fd = "fd ${args}"; }; in mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; programs.bash.shellAliases = optionsAlias; diff --git a/modules/programs/feh.nix b/modules/programs/feh.nix index bef9caac3..b96c9a27a 100644 --- a/modules/programs/feh.nix +++ b/modules/programs/feh.nix @@ -33,7 +33,7 @@ in { options.programs.feh = { enable = mkEnableOption "feh - a fast and light image viewer"; - package = mkPackageOption pkgs "feh" { }; + package = mkPackageOption pkgs "feh" { nullable = true; }; buttons = mkOption { default = { }; @@ -104,7 +104,7 @@ in { "To disable a keybinding, use `null` instead of an empty string."; }]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."feh/buttons" = mkIf (cfg.buttons != { }) { text = renderBindings cfg.buttons + "\n"; }; diff --git a/modules/programs/firefox.nix b/modules/programs/firefox.nix index 9379a2b9b..01cab9bd8 100644 --- a/modules/programs/firefox.nix +++ b/modules/programs/firefox.nix @@ -18,12 +18,8 @@ in { unwrappedPackageName = "firefox-unwrapped"; visible = true; - platforms.linux = rec { - vendorPath = ".mozilla"; - configPath = "${vendorPath}/firefox"; - }; + platforms.linux = rec { configPath = ".mozilla/firefox"; }; platforms.darwin = { - vendorPath = "Library/Application Support/Mozilla"; configPath = "Library/Application Support/Firefox"; }; }) diff --git a/modules/programs/firefox/mkFirefoxModule.nix b/modules/programs/firefox/mkFirefoxModule.nix index db787124c..341c8ba12 100644 --- a/modules/programs/firefox/mkFirefoxModule.nix +++ b/modules/programs/firefox/mkFirefoxModule.nix @@ -30,23 +30,6 @@ let profilesPath = if isDarwin then "${cfg.configPath}/Profiles" else cfg.configPath; - nativeMessagingHostsPath = if isDarwin then - "${cfg.vendorPath}/NativeMessagingHosts" - else - "${cfg.vendorPath}/native-messaging-hosts"; - - nativeMessagingHostsJoined = pkgs.symlinkJoin { - name = "ff_native-messaging-hosts"; - paths = [ - # Link a .keep file to keep the directory around - (pkgs.writeTextDir "lib/mozilla/native-messaging-hosts/.keep" "") - # Link package configured native messaging hosts (entire browser actually) - cfg.finalPackage - ] - # Link user configured native messaging hosts - ++ cfg.nativeMessagingHosts; - }; - # The extensions path shared by all profiles; will not be supported # by future browser versions. extensionPath = "extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"; @@ -73,10 +56,10 @@ let else builtins.toJSON pref); - mkUserJs = prePrefs: prefs: extraPrefs: bookmarks: extensions: + mkUserJs = prePrefs: prefs: extraPrefs: bookmarksFile: extensions: let - prefs' = lib.optionalAttrs ([ ] != bookmarks) { - "browser.bookmarks.file" = toString (browserBookmarksFile bookmarks); + prefs' = lib.optionalAttrs (bookmarksFile != null) { + "browser.bookmarks.file" = toString bookmarksFile; "browser.places.importBookmarksHTML" = true; } // lib.optionalAttrs (extensions != { }) { "extensions.webextensions.ExtensionStorageIDB.enabled" = false; @@ -129,59 +112,6 @@ let }} ''; - browserBookmarksFile = bookmarks: - let - indent = level: - lib.concatStringsSep "" (map (lib.const " ") (lib.range 1 level)); - - bookmarkToHTML = indentLevel: bookmark: - '' - ${indent indentLevel}
${escapeXML bookmark.name}''; - - directoryToHTML = indentLevel: directory: '' - ${indent indentLevel}
${ - if directory.toolbar then - '' -

Bookmarks Toolbar'' - else - ''

${escapeXML directory.name}'' - }

- ${indent indentLevel}

- ${allItemsToHTML (indentLevel + 1) directory.bookmarks} - ${indent indentLevel}

''; - - itemToHTMLOrRecurse = indentLevel: item: - if item ? "url" then - bookmarkToHTML indentLevel item - else - directoryToHTML indentLevel item; - - allItemsToHTML = indentLevel: bookmarks: - lib.concatStringsSep "\n" - (map (itemToHTMLOrRecurse indentLevel) bookmarks); - - bookmarkEntries = allItemsToHTML 1 bookmarks; - in pkgs.writeText "${packageName}-bookmarks.html" '' - - - - Bookmarks -

Bookmarks Menu

-

- ${bookmarkEntries} -

- ''; - mkNoDuplicateAssertion = entities: entityKind: (let # Return an attribute set with entity IDs as keys and a list of @@ -224,9 +154,12 @@ let package.override (old: { cfg = old.cfg or { } // fcfg; extraPolicies = (old.extraPolicies or { }) // cfg.policies; + pkcs11Modules = (old.pkcs11Modules or [ ]) ++ cfg.pkcs11Modules; }) else (pkgs.wrapFirefox.override { config = bcfg; }) package { }; + + bookmarkTypes = import ./profiles/bookmark-types.nix { inherit lib; }; in { options = setAttrByPath modulePath { enable = mkOption { @@ -296,11 +229,7 @@ in { vendorPath = mkOption { internal = true; type = with types; nullOr str; - default = with platforms; - if isDarwin then - darwin.vendorPath or null - else - linux.vendorPath or null; + default = null; example = ".mozilla"; description = "Directory containing the native messaging hosts directory."; @@ -315,7 +244,7 @@ in { description = "Directory containing the ${appName} configuration files."; }; - nativeMessagingHosts = optionalAttrs (cfg.vendorPath != null) (mkOption { + nativeMessagingHosts = mkOption { inherit visible; type = types.listOf types.package; default = [ ]; @@ -323,7 +252,7 @@ in { Additional packages containing native messaging hosts that should be made available to ${appName} extensions. ''; - }); + }; finalPackage = mkOption { inherit visible; @@ -354,6 +283,8 @@ in { profiles = mkOption { inherit visible; type = types.attrsOf (types.submodule ({ config, name, ... }: { + imports = [ (pkgs.path + "/nixos/modules/misc/assertions.nix") ]; + options = { name = mkOption { type = types.str; @@ -421,7 +352,7 @@ in { }; userChrome = mkOption { - type = types.lines; + type = types.oneOf [ types.lines types.path ]; default = ""; description = "Custom ${appName} user chrome CSS."; example = '' @@ -440,7 +371,7 @@ in { }; userContent = mkOption { - type = types.lines; + type = types.oneOf [ types.lines types.path ]; default = ""; description = "Custom ${appName} user content CSS."; example = '' @@ -450,104 +381,36 @@ in { }; bookmarks = mkOption { + type = (with types; + coercedTo bookmarkTypes.settingsType (bookmarks: + if bookmarks != { } then + warn '' + ${cfg.name} bookmarks have been refactored into a submodule that now explicitly require a 'force' option to be enabled. + + Replace: + + ${moduleName}.profiles.${name}.bookmarks = [ ... ]; + + With: + + ${moduleName}.profiles.${name}.bookmarks = { + force = true; + settings = [ ... ]; + }; + '' { + force = true; + settings = bookmarks; + } + else + { }) (submodule ({ config, ... }: + import ./profiles/bookmarks.nix { + inherit config lib pkgs; + modulePath = modulePath + ++ [ "profiles" name "bookmarks" ]; + }))); + default = { }; internal = !enableBookmarks; - type = let - bookmarkSubmodule = types.submodule ({ config, name, ... }: { - options = { - name = mkOption { - type = types.str; - default = name; - description = "Bookmark name."; - }; - - tags = mkOption { - type = types.listOf types.str; - default = [ ]; - description = "Bookmark tags."; - }; - - keyword = mkOption { - type = types.nullOr types.str; - default = null; - description = "Bookmark search keyword."; - }; - - url = mkOption { - type = types.str; - description = "Bookmark url, use %s for search terms."; - }; - }; - }) // { - description = "bookmark submodule"; - }; - - bookmarkType = types.addCheck bookmarkSubmodule (x: x ? "url"); - - directoryType = types.submodule ({ config, name, ... }: { - options = { - name = mkOption { - type = types.str; - default = name; - description = "Directory name."; - }; - - bookmarks = mkOption { - type = types.listOf nodeType; - default = [ ]; - description = "Bookmarks within directory."; - }; - - toolbar = mkOption { - type = types.bool; - default = false; - description = '' - Make this the toolbar directory. Note, this does _not_ - mean that this directory will be added to the toolbar, - this directory _is_ the toolbar. - ''; - }; - }; - }) // { - description = "directory submodule"; - }; - - nodeType = types.either bookmarkType directoryType; - in with types; - coercedTo (attrsOf nodeType) attrValues (listOf nodeType); - default = [ ]; - example = literalExpression '' - [ - { - name = "wikipedia"; - tags = [ "wiki" ]; - keyword = "wiki"; - url = "https://en.wikipedia.org/wiki/Special:Search?search=%s&go=Go"; - } - { - name = "kernel.org"; - url = "https://www.kernel.org"; - } - { - name = "Nix sites"; - toolbar = true; - bookmarks = [ - { - name = "homepage"; - url = "https://nixos.org/"; - } - { - name = "wiki"; - tags = [ "wiki" "nix" ]; - url = "https://wiki.nixos.org/"; - } - ]; - } - ] - ''; - description = '' - Preloaded bookmarks. Note, this may silently overwrite any - previously existing bookmarks! - ''; + description = "Declarative bookmarks."; }; path = mkOption { @@ -783,6 +646,26 @@ in { ''; }; }; + + config = { + assertions = [ + (mkNoDuplicateAssertion config.containers "container") + { + assertion = config.extensions.settings == { } + || config.extensions.force; + message = '' + Using '${ + lib.showAttrPath (modulePath + ++ [ "profiles" config.name "extensions" "settings" ]) + }' will override all previous extensions settings. + Enable '${ + lib.showAttrPath (modulePath + ++ [ "profiles" config.name "extensions" "force" ]) + }' to acknowledge this. + ''; + } + ] ++ config.bookmarks.assertions; + }; })); default = { }; description = "Attribute set of ${appName} profiles."; @@ -799,6 +682,14 @@ in { `true`. ''; }; + + pkcs11Modules = mkOption { + type = types.listOf types.package; + default = [ ]; + description = '' + Additional packages to be loaded as PKCS #11 modules in Firefox. + ''; + }; }; config = mkIf cfg.enable ({ @@ -838,58 +729,52 @@ in { } (mkNoDuplicateAssertion cfg.profiles "profile") - ] ++ (mapAttrsToList - (_: profile: mkNoDuplicateAssertion profile.containers "container") - cfg.profiles) ++ (mapAttrsToList (profileName: profile: { - assertion = profile.extensions.settings == { } - || profile.extensions.force; - message = '' - Using '${ - lib.showAttrPath - (modulePath ++ [ "profiles" profileName "extensions" "settings" ]) - }' will override all previous extensions settings. - Enable '${ - lib.showAttrPath - (modulePath ++ [ "profiles" profileName "extensions" "force" ]) - }' to acknowledge this. - ''; - }) cfg.profiles); + ] ++ (concatMap (profile: profile.assertions) (attrValues cfg.profiles)); warnings = optional (cfg.enableGnomeExtensions or false) '' Using '${moduleName}.enableGnomeExtensions' has been deprecated and will be removed in the future. Please change to overriding the package configuration using '${moduleName}.package' instead. You can refer to its example for how to do this. + '' ++ optional (cfg.vendorPath != null) '' + Using '${moduleName}.vendorPath' has been deprecated and + will be removed in the future. Native messaging hosts will function normally without specifying this path. ''; home.packages = lib.optional (cfg.finalPackage != null) cfg.finalPackage; + mozilla.firefoxNativeMessagingHosts = cfg.nativeMessagingHosts + # package configured native messaging hosts (entire browser actually) + ++ (lib.optional (cfg.finalPackage != null) cfg.finalPackage); + home.file = mkMerge ([{ "${cfg.configPath}/profiles.ini" = mkIf (cfg.profiles != { }) { text = profilesIni; }; - }] ++ optional (cfg.vendorPath != null) { - "${nativeMessagingHostsPath}" = { - source = - "${nativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts"; - recursive = true; - }; - } ++ flip mapAttrsToList cfg.profiles (_: profile: + }] ++ flip mapAttrsToList cfg.profiles (_: profile: # Merge the regular profile settings with extension settings mkMerge ([{ "${profilesPath}/${profile.path}/.keep".text = ""; "${profilesPath}/${profile.path}/chrome/userChrome.css" = - mkIf (profile.userChrome != "") { text = profile.userChrome; }; + mkIf (profile.userChrome != "") (let + key = + if builtins.isString profile.userChrome then "text" else "source"; + in { "${key}" = profile.userChrome; }); "${profilesPath}/${profile.path}/chrome/userContent.css" = - mkIf (profile.userContent != "") { text = profile.userContent; }; + mkIf (profile.userContent != "") (let + key = if builtins.isString profile.userContent then + "text" + else + "source"; + in { "${key}" = profile.userContent; }); "${profilesPath}/${profile.path}/user.js" = mkIf (profile.preConfig != "" || profile.settings != { } || profile.extraConfig != "" - || profile.bookmarks != [ ]) { + || profile.bookmarks.configFile != null) { text = mkUserJs profile.preConfig profile.settings profile.extraConfig - profile.bookmarks profile.extensions.settings; + profile.bookmarks.configFile profile.extensions.settings; }; "${profilesPath}/${profile.path}/containers.json" = @@ -922,7 +807,7 @@ in { (name: settingConfig: { "${profilesPath}/${profile.path}/browser-extension-data/${name}/storage.js" = { - force = settingConfig.force; + force = settingConfig.force || profile.extensions.force; text = generators.toJSON { } settingConfig.settings; }; }) profile.extensions.settings))))); diff --git a/modules/programs/firefox/profiles/bookmark-types.nix b/modules/programs/firefox/profiles/bookmark-types.nix new file mode 100644 index 000000000..64b1032be --- /dev/null +++ b/modules/programs/firefox/profiles/bookmark-types.nix @@ -0,0 +1,75 @@ +{ lib, ... }: + +let + + inherit (builtins) attrValues; + inherit (lib) types mkOption; + +in rec { + settingsType = with types; + coercedTo (addCheck (attrsOf nodeType) + # Check whether attribute set is of correct type + (attrs: !(attrs ? settings) || nodeType.check attrs.settings)) attrValues + (listOf nodeType); + + bookmarkSubmodule = types.submodule ({ name, ... }: { + options = { + name = mkOption { + type = types.str; + default = name; + description = "Bookmark name."; + }; + + tags = mkOption { + type = types.listOf types.str; + default = [ ]; + description = "Bookmark tags."; + }; + + keyword = mkOption { + type = types.nullOr types.str; + default = null; + description = "Bookmark search keyword."; + }; + + url = mkOption { + type = types.str; + description = "Bookmark url, use %s for search terms."; + }; + }; + }) // { + description = "bookmark submodule"; + }; + + bookmarkType = types.addCheck bookmarkSubmodule (x: x ? "url"); + + directoryType = types.submodule ({ name, ... }: { + options = { + name = mkOption { + type = types.str; + default = name; + description = "Directory name."; + }; + + bookmarks = mkOption { + type = types.listOf nodeType; + default = [ ]; + description = "Bookmarks within directory."; + }; + + toolbar = mkOption { + type = types.bool; + default = false; + description = '' + Make this the toolbar directory. Note, this does _not_ + mean that this directory will be added to the toolbar, + this directory _is_ the toolbar. + ''; + }; + }; + }) // { + description = "directory submodule"; + }; + + nodeType = types.either bookmarkType directoryType; +} diff --git a/modules/programs/firefox/profiles/bookmarks.nix b/modules/programs/firefox/profiles/bookmarks.nix new file mode 100644 index 000000000..bfdd43716 --- /dev/null +++ b/modules/programs/firefox/profiles/bookmarks.nix @@ -0,0 +1,146 @@ +{ config, lib, pkgs, modulePath }: + +let + inherit (lib) + escapeXML concatStringsSep mkOption maintainers types literalExpression; + + inherit (bookmarkTypes) settingsType; + + bookmarkTypes = import ./bookmark-types.nix { inherit lib; }; + + bookmarksFile = bookmarks: + let + indent = level: + lib.concatStringsSep "" (map (lib.const " ") (lib.range 1 level)); + + bookmarkToHTML = indentLevel: bookmark: + '' + ${indent indentLevel}
${escapeXML bookmark.name}''; + + directoryToHTML = indentLevel: directory: '' + ${indent indentLevel}
${ + if directory.toolbar then + '' +

Bookmarks Toolbar'' + else + ''

${escapeXML directory.name}'' + }

+ ${indent indentLevel}

+ ${allItemsToHTML (indentLevel + 1) directory.bookmarks} + ${indent indentLevel}

''; + + itemToHTMLOrRecurse = indentLevel: item: + if item ? "url" then + bookmarkToHTML indentLevel item + else + directoryToHTML indentLevel item; + + allItemsToHTML = indentLevel: bookmarks: + lib.concatStringsSep "\n" + (map (itemToHTMLOrRecurse indentLevel) bookmarks); + + bookmarkEntries = allItemsToHTML 1 bookmarks; + in pkgs.writeText "bookmarks.html" '' + + + + Bookmarks +

Bookmarks Menu

+

+ ${bookmarkEntries} +

+ ''; +in { + imports = [ + (pkgs.path + "/nixos/modules/misc/assertions.nix") + (pkgs.path + "/nixos/modules/misc/meta.nix") + ]; + + # We're currently looking for a maintainer who actively uses bookmarks! + meta.maintainers = with maintainers; [ kira-bruneau ]; + + options = { + enable = mkOption { + type = with types; bool; + default = config.settings != [ ]; + internal = true; + }; + + force = mkOption { + type = with types; bool; + default = false; + description = '' + Whether to force override existing custom bookmarks. + ''; + }; + + settings = mkOption { + type = settingsType; + default = [ ]; + example = literalExpression '' + [ + { + name = "wikipedia"; + tags = [ "wiki" ]; + keyword = "wiki"; + url = "https://en.wikipedia.org/wiki/Special:Search?search=%s&go=Go"; + } + { + name = "kernel.org"; + url = "https://www.kernel.org"; + } + { + name = "Nix sites"; + toolbar = true; + bookmarks = [ + { + name = "homepage"; + url = "https://nixos.org/"; + } + { + name = "wiki"; + tags = [ "wiki" "nix" ]; + url = "https://wiki.nixos.org/"; + } + ]; + } + ] + ''; + description = '' + Custom bookmarks. + ''; + }; + + configFile = mkOption { + type = with types; nullOr path; + default = if config.enable then bookmarksFile config.settings else null; + description = '' + Configuration file to define custom bookmarks. + ''; + }; + }; + + config = { + assertions = [{ + assertion = config.enable -> config.force; + message = '' + Using '${ + lib.showAttrPath (modulePath ++ [ "settings" ]) + }' will override all previous bookmarks. + Enable ${ + lib.showAttrPath (modulePath ++ [ "force" ]) + }' to acknowledge this. + ''; + }]; + }; +} diff --git a/modules/programs/firefox/profiles/search.nix b/modules/programs/firefox/profiles/search.nix index 99a226744..5b56aba1b 100644 --- a/modules/programs/firefox/profiles/search.nix +++ b/modules/programs/firefox/profiles/search.nix @@ -12,11 +12,8 @@ let "name" "isAppProvided" "loadPath" - "hasPreferredIcon" "updateInterval" "updateURL" - "iconUpdateURL" - "iconURL" "iconMapObj" "metaData" "orderHint" @@ -26,36 +23,44 @@ let searchForm = "__searchForm"; }; + # Convenience to specify absolute path to icon + iconUrl = icon: + if isPath icon || hasPrefix "/" icon then "file://${icon}" else icon; + processCustomEngineInput = input: - (removeAttrs input [ "icon" ]) // optionalAttrs (input ? icon) { - # Convenience to specify absolute path to icon - iconURL = "file://${input.icon}"; - } // (optionalAttrs (input ? iconUpdateURL) { - # Convenience to default iconURL to iconUpdateURL so - # the icon is immediately downloaded from the URL - iconURL = input.iconURL or input.iconUpdateURL; + { + name = input.id; + } // (removeAttrs input [ "icon" ]) + // optionalAttrs (input ? icon || input ? iconMapObj) { + iconMapObj = mapAttrs (name: iconUrl) ((optionalAttrs (input ? icon) { + # Convenience to specify single icon instead of map + "16" = input.icon; + }) // (input.iconMapObj or { })); } // { # Required for custom engine configurations, loadPaths # are unique identifiers that are generally formatted # like: [source]/path/to/engine.xml loadPath = "[home-manager]/${ - concatStringsSep "." (map strings.escapeNixIdentifier - (modulePath ++ [ "engines" input.name ])) + lib.showAttrPath (modulePath ++ [ "engines" input.id ]) }"; - }); + }; - processEngineInput = name: input: + processEngineInput = id: input: let requiredInput = { - inherit name; - isAppProvided = input.isAppProvided or removeAttrs input [ "metaData" ] - == { }; + inherit id; + isAppProvided = + input.isAppProvided or (removeAttrs input [ "metaData" ] == { }); metaData = input.metaData or { }; }; in if requiredInput.isAppProvided then requiredInput else - processCustomEngineInput (input // requiredInput); + pipe (input // requiredInput) [ + migrateEngineToV11 + migrateEngineToV12 + processCustomEngineInput + ]; buildEngineConfig = name: input: mapAttrs' (name: value: { @@ -65,10 +70,10 @@ let sortEngineConfigs = configs: let - buildEngineConfigWithOrder = order: name: + buildEngineConfigWithOrder = order: id: let - config = configs.${name} or { - _name = name; + config = configs.${id} or { + inherit id; _isAppProvided = true; _metaData = { }; }; @@ -89,15 +94,15 @@ let }; settings = { - version = 6; + version = 12; engines = sortEngineConfigs (mapAttrs buildEngineConfig engineInput); metaData = optionalAttrs (config.default != null) { - current = config.default; - hash = "@hash@"; + defaultEngineId = config.default; + defaultEngineIdHash = "@hash@"; } // optionalAttrs (config.privateDefault != null) { - private = config.privateDefault; - privateHash = "@privateHash@"; + privateDefaultEngineId = config.privateDefault; + privateDefaultEngineIdHash = "@privateHash@"; } // { useSavedOrder = config.order != [ ]; }; @@ -155,6 +160,204 @@ let mozlz4a <(echo "$json") "$out" fi ''; + + engineNameToId = { + # Derived from https://searchfox.org/mozilla-central/rev/e3f42ec9320748b2aab3d474d1e47075def9000c/services/settings/dumps/main/search-config-v2.json + "1&1 Suche" = "1und1"; + "Allegro" = "allegro-pl"; + "Amazon.co.jp" = "amazon-jp"; + "Amazon.com" = "amazondotcom-us"; + "Azerdict" = "azerdict"; + "百度" = "baidu"; + "Bing" = "bing"; + "Ordbok" = "bok-NO"; + "Ceneje.si" = "ceneji"; + "Cốc Cốc" = "coccoc"; + "다음" = "daum-kr"; + "DuckDuckGo" = "ddg"; + "eBay" = "ebay"; + "Ecosia" = "ecosia"; + "EUdict Eng->Cro" = "eudict"; + "Am Faclair Beag" = "faclair-beag"; + "GMX Suche" = "gmx-de"; + "GMX Search" = "gmx-en-GB"; + "GMX - Búsqueda web" = "gmx-es"; + "GMX - Recherche web" = "gmx-fr"; + "GMX Shopping" = "gmx-shopping"; + "Google" = "google"; + "Gule sider" = "gulesider-NO"; + "LEO Eng-Deu" = "leo_ende_de"; + "พจนานุกรม ลองดู" = "longdo"; + "mail.com search" = "mailcom"; + "Mapy.cz" = "mapy-cz"; + "MercadoLibre Argentina" = "mercadolibre-ar"; + "MercadoLibre Chile" = "mercadolibre-cl"; + "MercadoLibre Mexico" = "mercadolibre-mx"; + "MercadoLivre" = "mercadolivre"; + "네이버" = "naver-kr"; + "Odpiralni Časi" = "odpiralni"; + "Pazaruvaj" = "pazaruvaj"; + "Priberam" = "priberam"; + "Prisjakt" = "prisjakt-sv-SE"; + "Qwant" = "qwant"; + "Qwant Junior" = "qwantjr"; + "楽天市場" = "rakuten"; + "Readmoo 讀墨電子書" = "readmoo"; + "Reddit" = "reddit"; + "Salidzini.lv" = "salidzinilv"; + "Seznam" = "seznam-cz"; + "Tyda.se" = "tyda-sv-SE"; + "Vatera.hu" = "vatera"; + "WEB.DE Suche" = "webde"; + "Wikipedia (en)" = "wikipedia"; + "Wikipedia (nn)" = "wikipedia-NN"; + "Wikipedia (nb)" = "wikipedia-NO"; + "Wikipedia (af)" = "wikipedia-af"; + "Biquipedia (an)" = "wikipedia-an"; + "ويكيبيديا (ar)" = "wikipedia-ar"; + "Wikipedia (ast)" = "wikipedia-ast"; + "Vikipediya (az)" = "wikipedia-az"; + "Вікіпедыя (be)" = "wikipedia-be"; + "Вікіпэдыя (be-tarask)" = "wikipedia-be-tarask"; + "Уикипедия (bg)" = "wikipedia-bg"; + "উইকিপিডিয়া (bn)" = "wikipedia-bn"; + "Wikipedia (br)" = "wikipedia-br"; + "Wikipedia (bs)" = "wikipedia-bs"; + "Viquipèdia (ca)" = "wikipedia-ca"; + "Wicipedia (cy)" = "wikipedia-cy"; + "Wikipedie (cs)" = "wikipedia-cz"; + "Wikipedia (da)" = "wikipedia-da"; + "Wikipedia (de)" = "wikipedia-de"; + "Wikipedija (dsb)" = "wikipedia-dsb"; + "Βικιπαίδεια (el)" = "wikipedia-el"; + "Vikipedio (eo)" = "wikipedia-eo"; + "Wikipedia (es)" = "wikipedia-es"; + "Vikipeedia (et)" = "wikipedia-et"; + "Wikipedia (eu)" = "wikipedia-eu"; + "ویکی‌پدیا (fa)" = "wikipedia-fa"; + "Wikipedia (fi)" = "wikipedia-fi"; + "Wikipédia (fr)" = "wikipedia-fr"; + "Wikipedy (fy)" = "wikipedia-fy-NL"; + "Vicipéid (ga)" = "wikipedia-ga-IE"; + "Uicipeid (gd)" = "wikipedia-gd"; + "Wikipedia (gl)" = "wikipedia-gl"; + "Vikipetã (gn)" = "wikipedia-gn"; + "વિકિપીડિયા (gu)" = "wikipedia-gu"; + "ויקיפדיה" = "wikipedia-he"; + "विकिपीडिया (hi)" = "wikipedia-hi"; + "Wikipedija (hr)" = "wikipedia-hr"; + "Wikipedija (hsb)" = "wikipedia-hsb"; + "Wikipédia (hu)" = "wikipedia-hu"; + "Վիքիպեդիա (hy)" = "wikipedia-hy"; + "Wikipedia (ia)" = "wikipedia-ia"; + "Wikipedia (id)" = "wikipedia-id"; + "Wikipedia (is)" = "wikipedia-is"; + "Wikipedia (it)" = "wikipedia-it"; + "Wikipedia (ja)" = "wikipedia-ja"; + "ვიკიპედია (ka)" = "wikipedia-ka"; + "Wikipedia (kab)" = "wikipedia-kab"; + "Уикипедия (kk)" = "wikipedia-kk"; + "វិគីភីឌា (km)" = "wikipedia-km"; + "ವಿಕಿಪೀಡಿಯ (kn)" = "wikipedia-kn"; + "위키백과 (ko)" = "wikipedia-kr"; + "Wikipedia (lij)" = "wikipedia-lij"; + "ວິກິພີເດຍ (lo)" = "wikipedia-lo"; + "Vikipedija (lt)" = "wikipedia-lt"; + "Vikipedeja (ltg)" = "wikipedia-ltg"; + "Vikipēdija (lv)" = "wikipedia-lv"; + "Википедија (mk)" = "wikipedia-mk"; + "विकिपीडिया (mr)" = "wikipedia-mr"; + "Wikipedia (ms)" = "wikipedia-ms"; + "ဝီကီပီးဒီးယား (my)" = "wikipedia-my"; + "विकिपिडिया (ne)" = "wikipedia-ne"; + "Wikipedia (nl)" = "wikipedia-nl"; + "Wikipèdia (oc)" = "wikipedia-oc"; + "ਵਿਕੀਪੀਡੀਆ (pa)" = "wikipedia-pa"; + "Wikipedia (pl)" = "wikipedia-pl"; + "Wikipédia (pt)" = "wikipedia-pt"; + "Wikipedia (rm)" = "wikipedia-rm"; + "Wikipedia (ro)" = "wikipedia-ro"; + "Википедия (ru)" = "wikipedia-ru"; + "විකිපීඩියා (si)" = "wikipedia-si"; + "Wikipédia (sk)" = "wikipedia-sk"; + "Wikipedija (sl)" = "wikipedia-sl"; + "Wikipedia (sq)" = "wikipedia-sq"; + "Википедија (sr)" = "wikipedia-sr"; + "Wikipedia (sv)" = "wikipedia-sv-SE"; + "விக்கிப்பீடியா (ta)" = "wikipedia-ta"; + "వికీపీడియా (te)" = "wikipedia-te"; + "วิกิพีเดีย" = "wikipedia-th"; + "Wikipedia (tl)" = "wikipedia-tl"; + "Vikipedi (tr)" = "wikipedia-tr"; + "Вікіпедія (uk)" = "wikipedia-uk"; + "ویکیپیڈیا (ur)" = "wikipedia-ur"; + "Vikipediya (uz)" = "wikipedia-uz"; + "Wikipedia (vi)" = "wikipedia-vi"; + "Wikipedia (wo)" = "wikipedia-wo"; + "维基百科" = "wikipedia-zh-CN"; + "Wikipedia (zh)" = "wikipedia-zh-TW"; + "ವಿಕ್ಷನರಿ (kn)" = "wiktionary-kn"; + "Wikiccionari (oc)" = "wiktionary-oc"; + "விக்சனரி (ta)" = "wiktionary-ta"; + "విక్షనరీ (te)" = "wiktionary-te"; + "Wolne Lektury" = "wolnelektury-pl"; + "Yahoo! JAPAN" = "yahoo-jp"; + "Yahoo!オークション" = "yahoo-jp-auctions"; + "YouTube" = "youtube"; + + # Derived from https://searchfox.org/mozilla-central/rev/e3f42ec9320748b2aab3d474d1e47075def9000c/toolkit/components/search/SearchSettings.sys.mjs#32-44 + "Wikipedia (hy)" = "wikipedia-hy"; + "Wikipedia (kn)" = "wikipedia-kn"; + "Vikipēdija" = "wikipedia-lv"; + "Wikipedia (no)" = "wikipedia-NO"; + "Wikipedia (el)" = "wikipedia-el"; + "Wikipedia (lt)" = "wikipedia-lt"; + "Wikipedia (my)" = "wikipedia-my"; + "Wikipedia (pa)" = "wikipedia-pa"; + "Wikipedia (pt)" = "wikipedia-pt"; + "Wikipedia (si)" = "wikipedia-si"; + "Wikipedia (tr)" = "wikipedia-tr"; + }; + + migrateEngineNameToIdV7 = engine: + if builtins.hasAttr engine engineNameToId then + warn "Search engines are now referenced by id instead of by name, use '${ + engineNameToId.${engine} + }' instead of '${engine}'" engineNameToId.${engine} + else + engine; + + migrateEngineToV11 = engine: + engine // lib.optionalAttrs (engine ? iconMapObj) { + iconMapObj = mapAttrs' (name: value: + let nameToIntResult = builtins.tryEval (toInt name); + in { + name = if nameToIntResult.success then + name + else + let size = toString (builtins.fromJSON name).width; + in warn + "JSON object names for 'iconMapObj' are deprecated, use '${size}' instead of '${name}'" + size; + + inherit value; + }) engine.iconMapObj; + }; + + migrateEngineToV12 = engine: + let + iconMapObj = optionalAttrs (engine ? iconURL) { + "16" = warn "'iconURL' is deprecated, use 'icon = ${ + strings.escapeNixString engine.iconURL + }' instead" engine.iconURL; + } // optionalAttrs (engine ? iconUpdateURL) { + "16" = warn "'iconUpdateURL' is deprecated, use 'icon = ${ + strings.escapeNixString engine.iconUpdateURL + }' instead" engine.iconUpdateURL; + } // (engine.iconMapObj or { }); + in throwIf (engine ? hasPreferredIcon) "hasPreferredIcon has been removed" + (removeAttrs engine [ "iconURL" "iconUpdateURL" ]) + // lib.optionalAttrs (iconMapObj != { }) { inherit iconMapObj; }; in { imports = [ (pkgs.path + "/nixos/modules/misc/meta.nix") ]; @@ -182,8 +385,10 @@ in { default = mkOption { type = with types; nullOr str; + apply = engine: + if engine != null then migrateEngineNameToIdV7 engine else null; default = null; - example = "DuckDuckGo"; + example = "ddg"; description = '' The default search engine used in the address bar and search bar. @@ -192,8 +397,10 @@ in { privateDefault = mkOption { type = with types; nullOr str; + apply = engine: + if engine != null then migrateEngineNameToIdV7 engine else null; default = null; - example = "DuckDuckGo"; + example = "ddg"; description = '' The default search engine used in the Private Browsing. ''; @@ -201,8 +408,9 @@ in { order = mkOption { type = with types; uniq (listOf str); + apply = builtins.map migrateEngineNameToIdV7; default = [ ]; - example = [ "DuckDuckGo" "Google" ]; + example = [ "ddg" "google" ]; description = '' The order the search engines are listed in. Any engines that aren't included in this list will be listed after these in an @@ -212,10 +420,17 @@ in { engines = mkOption { type = with types; attrsOf (attrsOf jsonFormat.type); + + apply = mapAttrs' (name: value: { + name = migrateEngineNameToIdV7 name; + inherit value; + }); + default = { }; example = literalExpression '' { - "Nix Packages" = { + nix-packages = { + name = "Nix Packages"; urls = [{ template = "https://search.nixos.org/packages"; params = [ @@ -228,15 +443,15 @@ in { definedAliases = [ "@np" ]; }; - "NixOS Wiki" = { - urls = [{ template = "https://wiki.nixos.org/index.php?search={searchTerms}"; }]; - iconUpdateURL = "https://wiki.nixos.org/favicon.png"; - updateInterval = 24 * 60 * 60 * 1000; # every day + nixos-wiki = { + name = "NixOS Wiki"; + urls = [{ template = "https://wiki.nixos.org/w/index.php?search={searchTerms}"; }]; + iconMapObj."16" = "https://wiki.nixos.org/favicon.ico"; definedAliases = [ "@nw" ]; }; - "Bing".metaData.hidden = true; - "Google".metaData.alias = "@g"; # builtin engines only support specifying one additional alias + bing.metaData.hidden = true; + google.metaData.alias = "@g"; # builtin engines only support specifying one additional alias } ''; @@ -245,7 +460,7 @@ in { only have {var}`metaData` specified will be treated as builtin to ${appName}. - See [SearchEngine.jsm](https://searchfox.org/mozilla-central/rev/669329e284f8e8e2bb28090617192ca9b4ef3380/toolkit/components/search/SearchEngine.jsm#1138-1177) + See [SearchEngine.jsm](https://searchfox.org/mozilla-central/rev/e3f42ec9320748b2aab3d474d1e47075def9000c/toolkit/components/search/SearchEngine.sys.mjs#890-923) in ${appName}'s source for available options. We maintain a mapping to let you specify all options in the referenced link without underscores, but it may fall out of date with future diff --git a/modules/programs/fish.nix b/modules/programs/fish.nix index 1fb313a86..d4f9751d9 100644 --- a/modules/programs/fish.nix +++ b/modules/programs/fish.nix @@ -167,6 +167,16 @@ let ''; }; + command = mkOption { + type = with types; nullOr str; + default = null; + description = '' + Specifies the command(s) for which the abbreviation should expand. If + set, the abbreviation will only expand when used as an argument to + the given command(s). + ''; + }; + setCursor = mkOption { type = with types; (either bool str); default = false; @@ -201,7 +211,7 @@ let (lib.generators.mkValueStringDefault { } v) ]; } { - inherit position regex function; + inherit position regex command function; set-cursor = setCursor; }; modifiers = if isAttrs def then mods else ""; @@ -439,7 +449,7 @@ in { for src in $srcs; do if [ -d $src/share/man ]; then find -L $src/share/man -type f \ - | xargs python ${cfg.package}/share/fish/tools/create_manpage_completions.py --directory $out \ + -exec python ${cfg.package}/share/fish/tools/create_manpage_completions.py --directory $out {} + \ > /dev/null fi done diff --git a/modules/programs/floorp.nix b/modules/programs/floorp.nix index f96b4bd74..75616b7ee 100644 --- a/modules/programs/floorp.nix +++ b/modules/programs/floorp.nix @@ -19,14 +19,8 @@ in { unwrappedPackageName = "floorp-unwrapped"; visible = true; - platforms.linux = { - configPath = ".floorp"; - vendorPath = ".mozilla"; - }; - platforms.darwin = { - configPath = "Library/Application Support/Floorp"; - vendorPath = "Library/Application Support/Mozilla"; - }; + platforms.linux = { configPath = ".floorp"; }; + platforms.darwin = { configPath = "Library/Application Support/Floorp"; }; }) ]; } diff --git a/modules/programs/freetube.nix b/modules/programs/freetube.nix index 77700fe55..c2df1163a 100644 --- a/modules/programs/freetube.nix +++ b/modules/programs/freetube.nix @@ -21,7 +21,7 @@ in { options.programs.freetube = { enable = mkEnableOption "FreeTube, a YT client for Windows, Mac, and Linux"; - package = mkPackageOption pkgs "freetube" { }; + package = mkPackageOption pkgs "freetube" { nullable = true; }; settings = mkOption { type = lib.types.attrs; @@ -44,7 +44,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."FreeTube/hm_settings.db" = { source = pkgs.writeText "hm_settings.db" (settings cfg.settings); diff --git a/modules/programs/fuzzel.nix b/modules/programs/fuzzel.nix index 5057c36d6..95c12c836 100644 --- a/modules/programs/fuzzel.nix +++ b/modules/programs/fuzzel.nix @@ -14,7 +14,7 @@ in { options.programs.fuzzel = { enable = mkEnableOption "fuzzel"; - package = mkPackageOption pkgs "fuzzel" { }; + package = mkPackageOption pkgs "fuzzel" { nullable = true; }; settings = mkOption { type = iniFormat.type; @@ -42,7 +42,7 @@ in { lib.platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."fuzzel/fuzzel.ini" = mkIf (cfg.settings != { }) { source = iniFormat.generate "fuzzel.ini" cfg.settings; diff --git a/modules/programs/fzf.nix b/modules/programs/fzf.nix index 6f45682ca..76c5e2c4b 100644 --- a/modules/programs/fzf.nix +++ b/modules/programs/fzf.nix @@ -195,8 +195,10 @@ in { # Note, since fzf unconditionally binds C-r we use `mkOrder` to make the # initialization show up a bit earlier. This is to make initialization of # other history managers, like mcfly or atuin, take precedence. - programs.zsh.initExtra = - mkIf cfg.enableZshIntegration (mkOrder 200 zshIntegration); + # Still needs to be initialized after oh-my-zsh (order 800), otherwise + # omz will take precedence. + programs.zsh.initContent = + mkIf cfg.enableZshIntegration (mkOrder 910 zshIntegration); programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration (mkOrder 200 fishIntegration); diff --git a/modules/programs/gallery-dl.nix b/modules/programs/gallery-dl.nix index 4f566e18b..7665d5c08 100644 --- a/modules/programs/gallery-dl.nix +++ b/modules/programs/gallery-dl.nix @@ -14,7 +14,7 @@ in { options.programs.gallery-dl = { enable = mkEnableOption "gallery-dl"; - package = mkPackageOption pkgs "gallery-dl" { }; + package = mkPackageOption pkgs "gallery-dl" { nullable = true; }; settings = mkOption { type = jsonFormat.type; @@ -34,7 +34,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."gallery-dl/config.json" = mkIf (cfg.settings != { }) { source = jsonFormat.generate "gallery-dl-settings" cfg.settings; diff --git a/modules/programs/gh-dash.nix b/modules/programs/gh-dash.nix index b351bb33a..e1d4aa7ca 100644 --- a/modules/programs/gh-dash.nix +++ b/modules/programs/gh-dash.nix @@ -12,7 +12,7 @@ in { options.programs.gh-dash = { enable = lib.mkEnableOption "GitHub CLI dashboard plugin"; - package = lib.mkPackageOption pkgs "gh-dash" { }; + package = lib.mkPackageOption pkgs "gh-dash" { nullable = true; }; settings = lib.mkOption { type = yamlFormat.type; @@ -32,9 +32,9 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; - programs.gh.extensions = [ cfg.package ]; + programs.gh.extensions = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."gh-dash/config.yml".source = yamlFormat.generate "gh-dash-config.yml" cfg.settings; diff --git a/modules/programs/ghostty.nix b/modules/programs/ghostty.nix index c0fe86208..80845a27c 100644 --- a/modules/programs/ghostty.nix +++ b/modules/programs/ghostty.nix @@ -31,7 +31,7 @@ in { package = lib.mkPackageOption pkgs "ghostty" { nullable = true; extraDescription = - "Set programs.ghostty.package to null on platfroms where ghostty is not available or marked broken"; + "Set programs.ghostty.package to null on platforms where ghostty is not available or marked broken"; }; settings = lib.mkOption { @@ -194,7 +194,7 @@ in { }) (lib.mkIf cfg.enableZshIntegration { - programs.zsh.initExtra = '' + programs.zsh.initContent = '' if [[ -n $GHOSTTY_RESOURCES_DIR ]]; then source "$GHOSTTY_RESOURCES_DIR"/shell-integration/zsh/ghostty-integration fi diff --git a/modules/programs/git-cliff.nix b/modules/programs/git-cliff.nix index cd7fb529d..ce9e26f39 100644 --- a/modules/programs/git-cliff.nix +++ b/modules/programs/git-cliff.nix @@ -13,7 +13,7 @@ in { options.programs.git-cliff = { enable = mkEnableOption "git-cliff changelog generator"; - package = mkPackageOption pkgs "git-cliff" { }; + package = mkPackageOption pkgs "git-cliff" { nullable = true; }; settings = mkOption { type = tomlFormat.type; @@ -34,7 +34,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile = { "git-cliff/cliff.toml" = mkIf (cfg.settings != { }) { diff --git a/modules/programs/git-worktree-switcher.nix b/modules/programs/git-worktree-switcher.nix index cb38f2e62..df191ae7c 100644 --- a/modules/programs/git-worktree-switcher.nix +++ b/modules/programs/git-worktree-switcher.nix @@ -33,7 +33,7 @@ in { optionalString cfg.enableBashIntegration (initScript "bash"); programs.fish.interactiveShellInit = optionalString cfg.enableFishIntegration (initScript "fish"); - programs.zsh.initExtra = + programs.zsh.initContent = optionalString cfg.enableZshIntegration (initScript "zsh"); }; } diff --git a/modules/programs/git.nix b/modules/programs/git.nix index ee5980656..a4d528d4d 100644 --- a/modules/programs/git.nix +++ b/modules/programs/git.nix @@ -283,6 +283,13 @@ in { package = mkPackageOption pkgs "difftastic" { }; + enableAsDifftool = mkEnableOption "" // { + description = '' + Enable the {command}`difftastic` syntax highlighter as a git difftool. + See . + ''; + }; + background = mkOption { type = types.enum [ "light" "dark" ]; default = "light"; @@ -411,6 +418,29 @@ in { ''; }; }; + + riff = { + enable = mkEnableOption "" // { + description = '' + Enable the riff diff highlighter. + See . + ''; + }; + + package = mkPackageOption pkgs "riffdiff" { }; + + commandLineOptions = mkOption { + type = types.listOf types.str; + default = [ ]; + example = literalExpression ''[ "--no-adds-only-special" ]''; + apply = concatStringsSep " "; + description = '' + Command line arguments to include in the RIFF environment variable. + + Run riff --help for a full list of options + ''; + }; + }; }; }; @@ -434,6 +464,7 @@ in { cfg.diff-so-fancy.enable cfg.difftastic.enable cfg.diff-highlight.enable + cfg.riff.enable ]; in count id enabled <= 1; message = @@ -465,7 +496,7 @@ in { genIdentity = name: account: with account; nameValuePair "sendemail.${name}" (if account.msmtp.enable then { - smtpServer = "${pkgs.msmtp}/bin/msmtp"; + sendmailCmd = "${pkgs.msmtp}/bin/msmtp"; envelopeSender = "auto"; from = "${realName} <${address}>"; } else @@ -632,18 +663,28 @@ in { }; }) - (mkIf cfg.difftastic.enable { - home.packages = [ cfg.difftastic.package ]; - - programs.git.iniContent = let - difftCommand = concatStringsSep " " [ - "${getExe cfg.difftastic.package}" - "--color ${cfg.difftastic.color}" - "--background ${cfg.difftastic.background}" - "--display ${cfg.difftastic.display}" - ]; - in { diff.external = difftCommand; }; - }) + (let + difftCommand = concatStringsSep " " [ + "${getExe cfg.difftastic.package}" + "--color ${cfg.difftastic.color}" + "--background ${cfg.difftastic.background}" + "--display ${cfg.difftastic.display}" + ]; + in (lib.mkMerge [ + (mkIf cfg.difftastic.enable { + home.packages = [ cfg.difftastic.package ]; + programs.git.iniContent = { diff.external = difftCommand; }; + }) + (mkIf cfg.difftastic.enableAsDifftool { + home.packages = [ cfg.difftastic.package ]; + programs.git.iniContent = { + diff = { tool = lib.mkDefault "difftastic"; }; + difftool = { + difftastic = { cmd = "${difftCommand} $LOCAL $REMOTE"; }; + }; + }; + }) + ])) (let deltaPackage = cfg.delta.package; @@ -678,5 +719,25 @@ in { }; }; }) + + (let riffExe = baseNameOf (getExe cfg.riff.package); + in mkIf cfg.riff.enable { + home.packages = [ cfg.riff.package ]; + + # https://github.com/walles/riff/blob/b17e6f17ce807c8652bc59cd46758661d23ce358/README.md#usage + programs.git.iniContent = { + pager = { + diff = riffExe; + log = riffExe; + show = riffExe; + }; + + interactive.diffFilter = "${riffExe} --color=on"; + }; + }) + + (mkIf (cfg.riff.enable && cfg.riff.commandLineOptions != "") { + home.sessionVariables.RIFF = cfg.riff.commandLineOptions; + }) ]); } diff --git a/modules/programs/gradle.nix b/modules/programs/gradle.nix index 8bf5d7898..f8bba3e46 100644 --- a/modules/programs/gradle.nix +++ b/modules/programs/gradle.nix @@ -50,7 +50,10 @@ in { ''; }; - package = mkPackageOption pkgs "gradle" { example = "pkgs.gradle_7"; }; + package = mkPackageOption pkgs "gradle" { + nullable = true; + example = "pkgs.gradle_7"; + }; settings = mkOption { type = types.submodule { freeformType = settingsFormat.type; }; @@ -95,7 +98,7 @@ in { config = let gradleHome = "${config.home.homeDirectory}/${cfg.home}"; in mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file = mkMerge ([{ "${cfg.home}/gradle.properties" = mkIf (cfg.settings != { }) { diff --git a/modules/programs/granted.nix b/modules/programs/granted.nix index d3a7e5e00..9128a917f 100644 --- a/modules/programs/granted.nix +++ b/modules/programs/granted.nix @@ -15,17 +15,26 @@ in { enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; }; + + enableFishIntegration = + lib.hm.shell.mkFishIntegrationOption { inherit config; }; }; config = mkIf cfg.enable { home.packages = [ package ]; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' function assume() { export GRANTED_ALIAS_CONFIGURED="true" source ${package}/bin/assume "$@" unset GRANTED_ALIAS_CONFIGURED } ''; + + programs.fish.functions.assume = mkIf cfg.enableFishIntegration '' + set -x GRANTED_ALIAS_CONFIGURED "true" + source ${package}/share/assume.fish $argv + set -e GRANTED_ALIAS_CONFIGURED + ''; }; } diff --git a/modules/programs/havoc.nix b/modules/programs/havoc.nix index c83a1c39a..5d48fbac1 100644 --- a/modules/programs/havoc.nix +++ b/modules/programs/havoc.nix @@ -13,7 +13,7 @@ in { options.programs.havoc = { enable = mkEnableOption "Havoc terminal"; - package = mkPackageOption pkgs "havoc" { }; + package = mkPackageOption pkgs "havoc" { nullable = true; }; settings = mkOption { type = iniFormat.type; @@ -54,7 +54,7 @@ in { assertions = [ (hm.assertions.assertPlatform "programs.havoc" pkgs platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."havoc.cfg" = mkIf (cfg.settings != { }) { source = iniFormat.generate "havoc.cfg" cfg.settings; diff --git a/modules/programs/helix.nix b/modules/programs/helix.nix index 840f5d82f..3119a06d4 100644 --- a/modules/programs/helix.nix +++ b/modules/programs/helix.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, ... }: - with lib; - let cfg = config.programs.helix; tomlFormat = pkgs.formats.toml { }; @@ -26,6 +24,20 @@ in { description = "Extra packages available to hx."; }; + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra lines to be appended to the config file. + Use this if you would like to maintain order for helix settings (eg. for minor modes) + ''; + example = literalExpression '' + [keys.normal.g] # Reverse Alphabetical Order + G = "goto_file_end" + g = "goto_file_start" + ''; + }; + defaultEditor = mkOption { type = types.bool; default = false; @@ -200,7 +212,13 @@ in { xdg.configFile = let settings = { "helix/config.toml" = mkIf (cfg.settings != { }) { - source = tomlFormat.generate "helix-config" cfg.settings; + source = let + configFile = tomlFormat.generate "config.toml" cfg.settings; + extraConfigFile = + pkgs.writeText "extra-config.toml" ("\n" + cfg.extraConfig); + in pkgs.runCommand "helix-config.toml" { } '' + cat ${configFile} ${extraConfigFile} >> $out + ''; }; "helix/languages.toml" = mkIf (cfg.languages != { }) { source = tomlFormat.generate "helix-languages-config" cfg.languages; @@ -210,10 +228,10 @@ in { }; }; - themes = (mapAttrs' (n: v: + themes = mapAttrs' (n: v: nameValuePair "helix/themes/${n}.toml" { source = tomlFormat.generate "helix-theme-${n}" v; - }) cfg.themes); + }) cfg.themes; in settings // themes; }; } diff --git a/modules/programs/himalaya.nix b/modules/programs/himalaya.nix index 2348e0f93..5cba5a2f1 100644 --- a/modules/programs/himalaya.nix +++ b/modules/programs/himalaya.nix @@ -122,7 +122,7 @@ in { options = { programs.himalaya = { enable = mkEnableOption "the email client Himalaya CLI"; - package = mkPackageOption pkgs "himalaya" { }; + package = mkPackageOption pkgs "himalaya" { nullable = true; }; settings = mkOption { type = types.submodule { freeformType = tomlFormat.type; }; default = { }; @@ -153,7 +153,7 @@ in { }; config = mkIf himalaya.enable { - home.packages = [ himalaya.package ]; + home.packages = lib.mkIf (himalaya.package != null) [ himalaya.package ]; xdg = { configFile."himalaya/config.toml".source = let @@ -164,17 +164,18 @@ in { allConfig = globalConfig // { accounts = accountsConfig; }; in tomlFormat.generate "himalaya.config.toml" allConfig; - desktopEntries.himalaya = mkIf pkgs.stdenv.hostPlatform.isLinux { - type = "Application"; - name = "himalaya"; - genericName = "Email Client"; - comment = "CLI to manage emails"; - terminal = true; - exec = "himalaya %u"; - categories = [ "Network" ]; - mimeType = [ "x-scheme-handler/mailto" "message/rfc822" ]; - settings = { Keywords = "email"; }; - }; + desktopEntries.himalaya = + mkIf (pkgs.stdenv.hostPlatform.isLinux && (himalaya.package != null)) { + type = "Application"; + name = "himalaya"; + genericName = "Email Client"; + comment = "CLI to manage emails"; + terminal = true; + exec = "himalaya %u"; + categories = [ "Network" ]; + mimeType = [ "x-scheme-handler/mailto" "message/rfc822" ]; + settings = { Keywords = "email"; }; + }; }; }; } diff --git a/modules/programs/hstr.nix b/modules/programs/hstr.nix index 6dc2c0a33..1af2fa0ef 100644 --- a/modules/programs/hstr.nix +++ b/modules/programs/hstr.nix @@ -30,7 +30,7 @@ in { eval "$(${cfg.package}/bin/hstr --show-configuration)" ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' eval "$(${cfg.package}/bin/hstr --show-zsh-configuration)" ''; }; diff --git a/modules/programs/htop.nix b/modules/programs/htop.nix index b4004942c..28699e4a1 100644 --- a/modules/programs/htop.nix +++ b/modules/programs/htop.nix @@ -166,12 +166,13 @@ in { config = mkIf cfg.enable { lib.htop = { - inherit fields modes leftMeters rightMeters bar text graph led blank; + inherit fields defaultFields modes leftMeters rightMeters bar text graph + led blank; }; home.packages = [ cfg.package ]; - xdg.configFile."htop/htoprc" = let + xdg.configFile."htop" = let defaults = { fields = if isDarwin then remove fields.M_SHARE defaultFields @@ -188,9 +189,9 @@ in { formatOptions = mapAttrsToList formatOption; in mkIf (cfg.settings != { }) { - text = - concatStringsSep "\n" (formatOptions before ++ formatOptions settings) - + "\n"; + source = pkgs.writeTextDir "htoprc" + (concatStringsSep "\n" (formatOptions before ++ formatOptions settings) + + "\n"); }; }; } diff --git a/modules/programs/hyprlock.nix b/modules/programs/hyprlock.nix index fe1014554..a59c133be 100644 --- a/modules/programs/hyprlock.nix +++ b/modules/programs/hyprlock.nix @@ -25,7 +25,7 @@ in { ''; }; - package = lib.mkPackageOption pkgs "hyprlock" { }; + package = lib.mkPackageOption pkgs "hyprlock" { nullable = true; }; settings = lib.mkOption { type = with lib.types; @@ -110,7 +110,7 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."hypr/hyprlock.conf" = let shouldGenerate = cfg.extraConfig != "" || cfg.settings != { }; diff --git a/modules/programs/i3status.nix b/modules/programs/i3status.nix index 17b1162e8..343418dc6 100644 --- a/modules/programs/i3status.nix +++ b/modules/programs/i3status.nix @@ -130,7 +130,7 @@ in { ''; }; - package = mkPackageOption pkgs "i3status" { }; + package = mkPackageOption pkgs "i3status" { nullable = true; }; }; config = mkIf cfg.enable { @@ -190,7 +190,7 @@ in { }; }; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."i3status/config".text = concatStringsSep "\n" ([ ] ++ optional (cfg.general != { }) (formatModule "general" cfg.general) diff --git a/modules/programs/iamb.nix b/modules/programs/iamb.nix new file mode 100644 index 000000000..83dd018a2 --- /dev/null +++ b/modules/programs/iamb.nix @@ -0,0 +1,47 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.programs.iamb; + tomlFormat = pkgs.formats.toml { }; +in { + options.programs.iamb = { + enable = lib.mkEnableOption "iamb"; + + package = lib.mkPackageOption pkgs "iamb" { nullable = true; }; + + settings = lib.mkOption { + type = tomlFormat.type; + default = { }; + example = lib.literalExpression '' + { + default_profile = "personal"; + settings = { + notifications.enabled = true; + image_preview.protocol = { + type = "kitty"; + size = { + height = 10; + width = 66; + }; + }; + }; + } + ''; + description = '' + Configuration written to + {file}`$XDG_CONFIG_HOME/iamb/config.toml`. + + See for the full list + of options. + ''; + }; + + }; + + config = lib.mkIf cfg.enable { + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + + xdg.configFile."iamb/config.toml" = lib.mkIf (cfg.settings != { }) { + source = tomlFormat.generate "iamb-config" cfg.settings; + }; + }; +} diff --git a/modules/programs/imv.nix b/modules/programs/imv.nix index 583c2c57c..2cad38134 100644 --- a/modules/programs/imv.nix +++ b/modules/programs/imv.nix @@ -16,7 +16,7 @@ in { enable = mkEnableOption "imv: a command line image viewer intended for use with tiling window managers"; - package = mkPackageOption pkgs "imv" { }; + package = mkPackageOption pkgs "imv" { nullable = true; }; settings = mkOption { default = { }; @@ -38,7 +38,7 @@ in { assertions = [ (hm.assertions.assertPlatform "programs.imv" pkgs platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile = mkIf (cfg.settings != { }) { "imv/config".text = toConfig cfg.settings; }; diff --git a/modules/programs/jetbrains-remote.nix b/modules/programs/jetbrains-remote.nix index 4a9c045a9..917fe87cf 100644 --- a/modules/programs/jetbrains-remote.nix +++ b/modules/programs/jetbrains-remote.nix @@ -31,7 +31,7 @@ in { "${ide}/bin/${ide.meta.mainProgram}-remote-dev-server registerBackendLocationForGateway || true"; lines = map mkLine cfg.ides; linesStr = '' - rm $HOME/.cache/JetBrains/RemoteDev/userProvidedDist/_nix_store* + rm $HOME/.cache/JetBrains/RemoteDev/userProvidedDist/_nix_store* || true '' + concatStringsSep "\n" lines; in hm.dag.entryAfter [ "writeBoundary" ] linesStr; }; diff --git a/modules/programs/jqp.nix b/modules/programs/jqp.nix new file mode 100644 index 000000000..e82bccb27 --- /dev/null +++ b/modules/programs/jqp.nix @@ -0,0 +1,33 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.programs.jqp; + + yamlFormat = pkgs.formats.yaml { }; +in { + options.programs.jqp = { + enable = lib.mkEnableOption "jqp, jq playground"; + + package = lib.mkPackageOption pkgs "jqp" { nullable = true; }; + + settings = lib.mkOption { + type = yamlFormat.type; + default = { }; + example = { + theme = { + name = "monokai"; + chromaStyleOverrides = { kc = "#009900 underline"; }; + }; + }; + description = "Jqp configuration"; + }; + }; + config = lib.mkIf cfg.enable { + home = { + packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + + file.".jqp.yaml" = lib.mkIf (cfg.settings != { }) { + source = yamlFormat.generate "jqp-config" cfg.settings; + }; + }; + }; +} diff --git a/modules/programs/jujutsu.nix b/modules/programs/jujutsu.nix index f0e1b4250..7ba71acbc 100644 --- a/modules/programs/jujutsu.nix +++ b/modules/programs/jujutsu.nix @@ -25,7 +25,7 @@ in { enable = mkEnableOption "a Git-compatible DVCS that is both simple and powerful"; - package = mkPackageOption pkgs "jujutsu" { }; + package = mkPackageOption pkgs "jujutsu" { nullable = true; }; ediff = mkOption { type = types.bool; @@ -54,7 +54,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file."${configDir}/jj/config.toml" = mkIf (cfg.settings != { }) { source = tomlFormat.generate "jujutsu-config" (cfg.settings diff --git a/modules/programs/k9s.nix b/modules/programs/k9s.nix index 0dd107883..b0d669822 100644 --- a/modules/programs/k9s.nix +++ b/modules/programs/k9s.nix @@ -24,7 +24,7 @@ in { enable = mkEnableOption "k9s - Kubernetes CLI To Manage Your Clusters In Style"; - package = mkPackageOption pkgs "k9s" { }; + package = mkPackageOption pkgs "k9s" { nullable = true; }; settings = mkOption { type = yamlFormat.type; @@ -182,7 +182,7 @@ in { enableXdgConfig = !isDarwin || config.xdg.enable; in mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile = mkIf enableXdgConfig ({ "k9s/config.yaml" = mkIf (cfg.settings != { }) { diff --git a/modules/programs/kakoune.nix b/modules/programs/kakoune.nix index 5e40952b9..7aed4125a 100644 --- a/modules/programs/kakoune.nix +++ b/modules/programs/kakoune.nix @@ -622,7 +622,7 @@ in { programs.kakoune = { enable = mkEnableOption "the kakoune text editor"; - package = mkPackageOption pkgs "kakoune-unwrapped" { }; + package = mkPackageOption pkgs "kakoune-unwrapped" { nullable = true; }; config = mkOption { type = types.nullOr configModule; @@ -656,6 +656,8 @@ in { List of kakoune plugins to install. To get a list of supported plugins run: {command}`nix-env -f '' -qaP -A kakounePlugins`. + + Requires `package` to not be set to have effect. ''; }; @@ -674,7 +676,13 @@ in { }; config = mkIf cfg.enable { - home.packages = [ kakouneWithPlugins ]; + warnings = optional (cfg.package == null && cfg.plugins != [ ]) '' + You have configured `plugins` for `kakoune` but have not set `package`. + + The listed plugins will not be installed. + ''; + + home.packages = lib.mkIf (cfg.package != null) [ kakouneWithPlugins ]; home.sessionVariables = mkIf cfg.defaultEditor { EDITOR = "kak"; }; xdg.configFile = mkMerge [ { "kak/kakrc".source = configFile; } diff --git a/modules/programs/keychain.nix b/modules/programs/keychain.nix index c428f40cf..efc30c7c2 100644 --- a/modules/programs/keychain.nix +++ b/modules/programs/keychain.nix @@ -93,7 +93,7 @@ in { programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration '' SHELL=fish eval (${shellCommand}) ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' eval "$(SHELL=zsh ${shellCommand})" ''; programs.nushell.extraConfig = mkIf cfg.enableNushellIntegration '' diff --git a/modules/programs/khal.nix b/modules/programs/khal.nix index a2e28e018..96879c52e 100644 --- a/modules/programs/khal.nix +++ b/modules/programs/khal.nix @@ -168,7 +168,7 @@ in { options.programs.khal = { enable = mkEnableOption "khal, a CLI calendar application"; - package = mkPackageOption pkgs "khal" { }; + package = mkPackageOption pkgs "khal" { nullable = true; }; locale = mkOption { type = lib.types.submodule { options = localeOptions; }; @@ -199,7 +199,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."khal/config".text = concatStringsSep "\n" ([ "[calendars]" ] ++ mapAttrsToList genCalendarStr khalAccounts ++ [ diff --git a/modules/programs/kitty.nix b/modules/programs/kitty.nix index 04dada1fa..9ccc87b54 100644 --- a/modules/programs/kitty.nix +++ b/modules/programs/kitty.nix @@ -22,6 +22,10 @@ let mkKeyValue = key: command: "map ${key} ${command}"; }; + toKittyActionAliases = lib.generators.toKeyValue { + mkKeyValue = alias_name: action: "action_alias ${alias_name} ${action}"; + }; + toKittyEnv = lib.generators.toKeyValue { mkKeyValue = name: value: "env ${name}=${value}"; }; @@ -143,6 +147,18 @@ in { description = "The font to use."; }; + actionAliases = mkOption { + type = types.attrsOf types.str; + default = { }; + description = "Define action aliases."; + example = literalExpression '' + { + "launch_tab" = "launch --cwd=current --type=tab"; + "launch_window" = "launch --cwd=current --type=os-window"; + } + ''; + }; + keybindings = mkOption { type = types.attrsOf types.str; default = { }; @@ -234,6 +250,7 @@ in { shell_integration ${cfg.shellIntegration.mode} '') (toKittyConfig cfg.settings) + (toKittyActionAliases cfg.actionAliases) (toKittyKeybindings cfg.keybindings) (toKittyEnv cfg.environment) cfg.extraConfig @@ -265,7 +282,7 @@ in { programs.fish.interactiveShellInit = mkIf cfg.shellIntegration.enableFishIntegration shellIntegrationInit.fish; - programs.zsh.initExtra = + programs.zsh.initContent = mkIf cfg.shellIntegration.enableZshIntegration shellIntegrationInit.zsh; }; } diff --git a/modules/programs/kubecolor.nix b/modules/programs/kubecolor.nix index d187c34d0..807a55550 100644 --- a/modules/programs/kubecolor.nix +++ b/modules/programs/kubecolor.nix @@ -25,6 +25,9 @@ in { ''; }; + enableZshIntegration = + lib.hm.shell.mkZshIntegrationOption { inherit config; }; + settings = mkOption { type = yamlFormat.type; default = { }; @@ -55,7 +58,13 @@ in { "kube/color.yaml"; in mkIf cfg.enable { - home.packages = [ cfg.package ]; + warnings = optional (cfg.package == null && cfg.plugins != [ ]) '' + You have configured `enableAlias` for `kubecolor` but have not set `package`. + + The alias will not be created. + ''; + + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.sessionVariables = if preferXdgDirectories then { KUBECOLOR_CONFIG = "${config.xdg.configHome}/${configPathSuffix}"; @@ -81,7 +90,15 @@ in { }; }; - home.shellAliases = - lib.mkIf cfg.enableAlias { kubectl = lib.getExe cfg.package; }; + home.shellAliases = lib.mkIf (cfg.enableAlias && (cfg.package != null)) { + kubectl = lib.getExe cfg.package; + oc = lib.mkIf (builtins.elem pkgs.openshift config.home.packages) + "env KUBECTL_COMMAND=${lib.getExe pkgs.openshift} ${ + lib.getExe cfg.package + }"; + }; + + programs.zsh.initContent = + lib.mkIf cfg.enableZshIntegration "compdef kubecolor=kubectl"; }; } diff --git a/modules/programs/lapce.nix b/modules/programs/lapce.nix index f3fd24f28..baf6f2404 100644 --- a/modules/programs/lapce.nix +++ b/modules/programs/lapce.nix @@ -7,7 +7,7 @@ let options = { enable = mkEnableOption "lapce"; - package = mkPackageOption pkgs "lapce" { }; + package = mkPackageOption pkgs "lapce" { nullable = true; }; channel = mkOption { type = types.enum [ "stable" "nightly" ]; default = "stable"; @@ -171,7 +171,7 @@ in { options.programs.lapce = options; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg = let dir = "lapce-${cfg.channel}"; in { diff --git a/modules/programs/lazydocker.nix b/modules/programs/lazydocker.nix new file mode 100644 index 000000000..2cceb1333 --- /dev/null +++ b/modules/programs/lazydocker.nix @@ -0,0 +1,60 @@ +{ config, lib, pkgs, ... }: + +let + + cfg = config.programs.lazydocker; + + yamlFormat = pkgs.formats.yaml { }; + + inherit (pkgs.stdenv.hostPlatform) isDarwin; + +in { + meta.maintainers = [ lib.maintainers.hausken ]; + + options.programs.lazydocker = { + enable = lib.mkEnableOption + "lazydocker, a simple terminal UI for both docker and docker compose"; + + package = lib.mkPackageOption pkgs "lazydocker" { nullable = true; }; + + settings = lib.mkOption { + type = yamlFormat.type; + default = { + commandTemplates.dockerCompose = + "docker compose"; # Lazydocker uses docker-compose by default which will not work + }; + example = lib.literalExpression '' + { + gui.theme = { + activeBorderColor = ["red" "bold"]; + inactiveBorderColor = ["blue"]; + }; + commandTemplates.dockerCompose = "docker compose compose -f docker-compose.yml"; + } + ''; + description = '' + Configuration written to + {file}`$XDG_CONFIG_HOME/lazydocker/config.yml` + on Linux or on Darwin if [](#opt-xdg.enable) is set, otherwise + {file}`~/Library/Application Support/jesseduffield/lazydocker/config.yml`. + See + + for supported values. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + + home.file."Library/Application Support/jesseduffield/lazydocker/config.yml" = + lib.mkIf (cfg.settings != { } && (isDarwin && !config.xdg.enable)) { + source = yamlFormat.generate "lazydocker-config" cfg.settings; + }; + + xdg.configFile."lazydocker/config.yml" = + lib.mkIf (cfg.settings != { } && !(isDarwin && !config.xdg.enable)) { + source = yamlFormat.generate "lazydocker-config" cfg.settings; + }; + }; +} diff --git a/modules/programs/lazygit.nix b/modules/programs/lazygit.nix index b7761b557..0c355c6dc 100644 --- a/modules/programs/lazygit.nix +++ b/modules/programs/lazygit.nix @@ -16,7 +16,7 @@ in { options.programs.lazygit = { enable = mkEnableOption "lazygit, a simple terminal UI for git commands"; - package = mkPackageOption pkgs "lazygit" { }; + package = mkPackageOption pkgs "lazygit" { nullable = true; }; settings = mkOption { type = yamlFormat.type; @@ -45,7 +45,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file."Library/Application Support/lazygit/config.yml" = mkIf (cfg.settings != { } && (isDarwin && !config.xdg.enable)) { diff --git a/modules/programs/ledger.nix b/modules/programs/ledger.nix index 1b9178d15..441fc1574 100644 --- a/modules/programs/ledger.nix +++ b/modules/programs/ledger.nix @@ -21,7 +21,7 @@ in { options.programs.ledger = { enable = mkEnableOption "ledger, a double-entry accounting system"; - package = mkPackageOption pkgs "ledger" { }; + package = mkPackageOption pkgs "ledger" { nullable = true; }; settings = mkOption { type = with types; attrsOf (oneOf [ bool int str (listOf str) ]); @@ -59,7 +59,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."ledger/ledgerrc" = mkIf (cfg.settings != { } || cfg.extraConfig != "") { diff --git a/modules/programs/librewolf.nix b/modules/programs/librewolf.nix index 0d2aec3b2..86f640c81 100644 --- a/modules/programs/librewolf.nix +++ b/modules/programs/librewolf.nix @@ -29,13 +29,9 @@ in { wrappedPackageName = "librewolf"; unwrappedPackageName = "librewolf-unwrapped"; - platforms.linux = { - configPath = ".librewolf"; - vendorPath = ".mozilla"; - }; + platforms.linux = { configPath = ".librewolf"; }; platforms.darwin = { configPath = "Library/Application Support/LibreWolf"; - vendorPath = "Library/Application Support/Mozilla"; }; enableBookmarks = false; @@ -61,11 +57,6 @@ in { }; config = mkIf cfg.enable { - assertions = [ - (lib.hm.assertions.assertPlatform "programs.librewolf" pkgs - lib.platforms.linux) - ]; - home.file.".librewolf/librewolf.overrides.cfg" = lib.mkIf (cfg.settings != { }) { text = mkOverridesFile cfg.settings; }; }; diff --git a/modules/programs/looking-glass-client.nix b/modules/programs/looking-glass-client.nix index 1c14282b9..c17802441 100644 --- a/modules/programs/looking-glass-client.nix +++ b/modules/programs/looking-glass-client.nix @@ -11,7 +11,7 @@ in { options.programs.looking-glass-client = { enable = mkEnableOption "looking-glass-client"; - package = mkPackageOption pkgs "looking-glass-client" { }; + package = mkPackageOption pkgs "looking-glass-client" { nullable = true; }; settings = mkOption { type = settingsFormat.type; @@ -50,7 +50,7 @@ in { platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."looking-glass/client.ini" = mkIf (cfg.settings != { }) { source = diff --git a/modules/programs/mbsync.nix b/modules/programs/mbsync.nix index 00371b7f1..f9dffd2f4 100644 --- a/modules/programs/mbsync.nix +++ b/modules/programs/mbsync.nix @@ -288,7 +288,8 @@ in { createMaildir = hm.dag.entryBetween [ "linkGeneration" ] [ "writeBoundary" ] '' run mkdir -m700 -p $VERBOSE_ARG ${ - concatMapStringsSep " " (a: a.maildir.absPath) mbsyncAccounts + concatMapStringsSep " " (a: escapeShellArg a.maildir.absPath) + mbsyncAccounts } ''; }; diff --git a/modules/programs/mcfly.nix b/modules/programs/mcfly.nix index cf115129d..ef5a98e64 100644 --- a/modules/programs/mcfly.nix +++ b/modules/programs/mcfly.nix @@ -7,22 +7,33 @@ let tomlFormat = pkgs.formats.toml { }; + # These shell integrations all wrap `mcfly-fzf init` in an interactive shell + # check, due to a buggy interactivity check in its initialization. + # See: https://github.com/nix-community/home-manager/issues/6663 + # and https://github.com/bnprks/mcfly-fzf/issues/10 + bashIntegration = '' eval "$(${getExe pkgs.mcfly} init bash)" '' + optionalString cfg.fzf.enable '' - eval "$(${getExe pkgs.mcfly-fzf} init bash)" + if [[ $- =~ i ]]; then + eval "$(${getExe pkgs.mcfly-fzf} init bash)" + fi ''; fishIntegration = '' ${getExe pkgs.mcfly} init fish | source '' + optionalString cfg.fzf.enable '' - ${getExe pkgs.mcfly-fzf} init fish | source + if status is-interactive + eval "$(${getExe pkgs.mcfly-fzf} init fish)" + end ''; zshIntegration = '' eval "$(${getExe pkgs.mcfly} init zsh)" '' + optionalString cfg.fzf.enable '' - eval "$(${getExe pkgs.mcfly-fzf} init zsh)" + if [[ -o interactive ]]; then + ${getExe pkgs.mcfly-fzf} init zsh | source + fi ''; in { @@ -130,7 +141,7 @@ in { programs.bash.initExtra = mkIf cfg.enableBashIntegration bashIntegration; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration zshIntegration; + programs.zsh.initContent = mkIf cfg.enableZshIntegration zshIntegration; programs.fish.shellInit = mkIf cfg.enableFishIntegration fishIntegration; diff --git a/modules/programs/mergiraf.nix b/modules/programs/mergiraf.nix new file mode 100644 index 000000000..0597b7d93 --- /dev/null +++ b/modules/programs/mergiraf.nix @@ -0,0 +1,31 @@ +{ pkgs, config, lib, ... }: +let + inherit (lib) + mkEnableOption mkPackageOption types literalExpression mkIf maintainers; + cfg = config.programs.mergiraf; + mergiraf = "${cfg.package}/bin/mergiraf"; +in { + meta.maintainers = [ maintainers.bobvanderlinden ]; + + options = { + programs.mergiraf = { + enable = mkEnableOption "mergiraf"; + package = mkPackageOption pkgs "mergiraf" { }; + }; + }; + + config = mkIf cfg.enable { + home.packages = [ cfg.package ]; + + programs.git = { + attributes = [ "* merge=mergiraf" ]; + extraConfig = { + merge.mergiraf = { + name = "mergiraf"; + driver = + "${mergiraf} merge --git %O %A %B -s %S -x %X -y %Y -p %P -l %L"; + }; + }; + }; + }; +} diff --git a/modules/programs/micro.nix b/modules/programs/micro.nix index bf34f8e62..acd768679 100644 --- a/modules/programs/micro.nix +++ b/modules/programs/micro.nix @@ -15,7 +15,7 @@ in { programs.micro = { enable = mkEnableOption "micro, a terminal-based text editor"; - package = mkPackageOption pkgs "micro" { }; + package = mkPackageOption pkgs "micro" { nullable = true; }; settings = mkOption { type = jsonFormat.type; @@ -37,7 +37,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."micro/settings.json".source = jsonFormat.generate "micro-settings" cfg.settings; diff --git a/modules/programs/mise.nix b/modules/programs/mise.nix index 67b0a4b57..f4bbcade4 100644 --- a/modules/programs/mise.nix +++ b/modules/programs/mise.nix @@ -29,7 +29,7 @@ in { programs.mise = { enable = mkEnableOption "mise"; - package = mkPackageOption pkgs "mise" { }; + package = mkPackageOption pkgs "mise" { nullable = true; }; enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { inherit config; }; @@ -83,7 +83,15 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + warnings = optional (cfg.package == null && (cfg.enableBashIntegration + || cfg.enableZshIntegration || cfg.enableFishIntegration + || cfg.enableNushellIntegration)) '' + You have enabled shell integration for `mise` but have not set `package`. + + The shell integration will not be added. + ''; + + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile = { "mise/config.toml" = mkIf (cfg.globalConfig != { }) { @@ -100,7 +108,7 @@ in { eval "$(${getExe cfg.package} activate bash)" ''; - zsh.initExtra = mkIf cfg.enableZshIntegration '' + zsh.initContent = mkIf cfg.enableZshIntegration '' eval "$(${getExe cfg.package} activate zsh)" ''; diff --git a/modules/programs/mods.nix b/modules/programs/mods.nix new file mode 100644 index 000000000..17a108e2e --- /dev/null +++ b/modules/programs/mods.nix @@ -0,0 +1,77 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.programs.mods; + yamlFormat = pkgs.formats.yaml { }; +in { + meta.maintainers = [ hm.maintainers.ipsavitsky ]; + + options.programs.mods = { + enable = mkEnableOption "mods"; + + package = mkOption { + type = types.package; + default = pkgs.mods; + defaultText = literalExpression "pkgs.mods"; + description = "The mods package to install"; + }; + + settings = mkOption { + type = yamlFormat.type; + default = { }; + example = '' + { + default-model = "llama3.2"; + apis = { + ollama = { + base-url = "http://localhost:11434/api"; + models = { + "llama3.2" = { + max-input-chars = 650000; + }; + }; + }; + }; + } + ''; + description = '' + Configuration written to + {file}`$XDG_CONFIG_HOME/mods/mods.yml`. + + See for the full + list of options. + ''; + }; + + enableBashIntegration = + lib.hm.shell.mkBashIntegrationOption { inherit config; }; + + enableZshIntegration = + lib.hm.shell.mkZshIntegrationOption { inherit config; }; + + enableFishIntegration = + lib.hm.shell.mkFishIntegrationOption { inherit config; }; + }; + + config = mkIf cfg.enable { + home.packages = [ cfg.package ]; + + xdg.configFile."mods/mods.yml" = mkIf (cfg.settings != { }) { + source = yamlFormat.generate "mods.yml" cfg.settings; + }; + + programs.bash.initExtra = mkIf cfg.enableBashIntegration (mkOrder 200 '' + source <(${cfg.package}/bin/mods completion bash) + ''); + + programs.zsh.initContent = mkIf cfg.enableZshIntegration (mkOrder 200 '' + source <(${cfg.package}/bin/mods completion zsh) + ''); + + programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration + (mkOrder 200 '' + ${cfg.package}/bin/mods completion fish | source + ''); + }; +} diff --git a/modules/programs/mr.nix b/modules/programs/mr.nix index 507189769..140aff32d 100644 --- a/modules/programs/mr.nix +++ b/modules/programs/mr.nix @@ -17,7 +17,7 @@ in { enable = mkEnableOption "mr, a tool to manage all your version control repositories"; - package = mkPackageOption pkgs "mr" { }; + package = mkPackageOption pkgs "mr" { nullable = true; }; settings = mkOption { type = iniFormat.type; @@ -42,7 +42,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file.".mrconfig".source = iniFormat.generate ".mrconfig" cfg.settings; }; } diff --git a/modules/programs/mu.nix b/modules/programs/mu.nix index f5ef51b0a..fdb85f85a 100644 --- a/modules/programs/mu.nix +++ b/modules/programs/mu.nix @@ -16,7 +16,8 @@ let filter (a: a.mu.enable) (attrValues config.accounts.email.accounts); addrs = map (a: a.address) muAccounts; # Construct list of lists containing email aliases, and flatten - aliases = flatten (map (a: a.aliases) muAccounts); + aliases = map (alias: alias.address or alias) + (flatten (map (a: a.aliases) muAccounts)); # Sort the list in sort lessThan (addrs ++ aliases); diff --git a/modules/programs/navi.nix b/modules/programs/navi.nix index 23fb04864..45c5003a8 100644 --- a/modules/programs/navi.nix +++ b/modules/programs/navi.nix @@ -7,7 +7,7 @@ let yamlFormat = pkgs.formats.yaml { }; - configDir = if pkgs.stdenv.isDarwin then + configDir = if pkgs.stdenv.isDarwin && !config.xdg.enable then "Library/Application Support" else config.xdg.configHome; @@ -66,7 +66,7 @@ in { fi ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' if [[ $options[zle] = on ]]; then eval "$(${cfg.package}/bin/navi widget zsh)" fi diff --git a/modules/programs/neomutt.nix b/modules/programs/neomutt.nix index 13ee897f1..8ef1a45cf 100644 --- a/modules/programs/neomutt.nix +++ b/modules/programs/neomutt.nix @@ -237,14 +237,16 @@ let else ''named-mailboxes "${extra.name}" "${mailboxroot}/${extra.mailbox}"'') account.neomutt.extraMailboxes; - in with account; '' - # register account ${name} - ${optionalString account.neomutt.showDefaultMailbox - ''${mailboxes} "${mailroot}/${folders.inbox}"''} - ${extraMailboxes} - ${hookName} ${mailroot}/ " \ - source ${accountFilename account} " - ''; + in with account; + [ "## register account ${name}" ] + ++ optional account.neomutt.showDefaultMailbox + ''${mailboxes} "${mailroot}/${folders.inbox}"'' ++ [ + extraMailboxes + '' + ${hookName} ${mailroot}/ " \ + source ${accountFilename account} " + '' + ]; mraSection = account: with account; @@ -300,7 +302,7 @@ let "set signature = ${ pkgs.writeText "signature.txt" account.signature.text }"; - in '' + in concatStringsSep "\n" (['' # Generated by Home Manager.${ optionalString cfg.unmailboxes '' @@ -323,21 +325,18 @@ let # MTA section ${optionsStr (mtaSection account)} + ''] ++ (lib.optional (cfg.checkStatsInterval != null) mailCheckSection) + ++ (lib.optional cfg.sidebar.enable sidebarSection) ++ ['' + # MRA section + ${mraSection account} - ${optionalString (cfg.checkStatsInterval != null) mailCheckSection} + # Extra configuration + ${account.neomutt.extraConfig} - ${optionalString cfg.sidebar.enable sidebarSection} - - # MRA section - ${mraSection account} - - # Extra configuration - ${account.neomutt.extraConfig} - - ${signature} - '' - + optionalString (account.notmuch.enable && account.notmuch.neomutt.enable) - (notmuchSection account); + ${signature} + ''] + ++ lib.optional (account.notmuch.enable && account.notmuch.neomutt.enable) + (notmuchSection account)); in { options = { @@ -454,43 +453,40 @@ in { # otherwise use the first neomutt account as primary. primary = head (filter (a: a.primary) neomuttAccounts ++ neomuttAccounts); - in '' - # Generated by Home Manager. - set header_cache = "${config.xdg.cacheHome}/neomutt/headers/" - set message_cachedir = "${config.xdg.cacheHome}/neomutt/messages/" - set editor = "${cfg.editor}" - set implicit_autoview = yes - set crypt_use_gpgme = yes + in concatStringsSep "\n" ([ + "# Generated by Home Manager." + ''set header_cache = "${config.xdg.cacheHome}/neomutt/headers/"'' + ''set message_cachedir = "${config.xdg.cacheHome}/neomutt/messages/"'' + ''set editor = "${cfg.editor}"'' + "set implicit_autoview = yes" + "set crypt_use_gpgme = yes" + "alternative_order text/enriched text/plain text" + "set delete = yes" + (optionalString cfg.vimKeys + "source ${pkgs.neomutt}/share/doc/neomutt/vim-keys/vim-keys.rc") + ] ++ (lib.optionals (cfg.binds != [ ]) [ + '' - alternative_order text/enriched text/plain text + # Binds'' + bindSection + ]) ++ [ + '' - set delete = yes - - ${optionalString cfg.vimKeys - "source ${pkgs.neomutt}/share/doc/neomutt/vim-keys/vim-keys.rc"} - - # Binds - ${bindSection} - - # Macros - ${macroSection} - - # Register accounts - ${ - optionalString (accountCommandNeeded) '' - set account_command = '${accountCommand}/bin/account-command.sh' - '' - }${concatMapStringsSep "\n" registerAccount neomuttAccounts} - - ${optionalString cfg.sourcePrimaryAccount '' + # Macros'' + macroSection + "# Register accounts" + (optionalString (accountCommandNeeded) '' + set account_command = '${accountCommand}/bin/account-command.sh' + '') + ] ++ (lib.flatten (map registerAccount neomuttAccounts)) ++ [ + (optionalString cfg.sourcePrimaryAccount '' # Source primary account - source ${accountFilename primary}''} - - # Extra configuration - ${optionsStr cfg.settings} - - ${cfg.extraConfig} - ''; + source ${accountFilename primary} + '') + "# Extra configuration" + (optionsStr cfg.settings) + cfg.extraConfig + ]); }; assertions = [{ diff --git a/modules/programs/neovide.nix b/modules/programs/neovide.nix index 3b40fb3eb..74d1a8e7b 100644 --- a/modules/programs/neovide.nix +++ b/modules/programs/neovide.nix @@ -11,7 +11,7 @@ in { options.programs.neovide = { enable = lib.mkEnableOption "Neovide, No Nonsense Neovim Client in Rust"; - package = lib.mkPackageOption pkgs "neovide" { }; + package = lib.mkPackageOption pkgs "neovide" { nullable = true; }; settings = lib.mkOption { type = settingsFormat.type; @@ -45,7 +45,7 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."neovide/config.toml".source = settingsFormat.generate "config.toml" cfg.settings; }; diff --git a/modules/programs/nheko.nix b/modules/programs/nheko.nix index 1bf1ae706..0e858b30e 100644 --- a/modules/programs/nheko.nix +++ b/modules/programs/nheko.nix @@ -24,7 +24,7 @@ in { options.programs.nheko = { enable = mkEnableOption "Qt desktop client for Matrix"; - package = mkPackageOption pkgs "nheko" { }; + package = mkPackageOption pkgs "nheko" { nullable = true; }; settings = mkOption { type = iniFmt.type; @@ -64,7 +64,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file."${configDir}/nheko/nheko.conf" = mkIf (cfg.settings != { }) { text = '' diff --git a/modules/programs/nix-index.nix b/modules/programs/nix-index.nix index f483cd2bc..23d3c979e 100644 --- a/modules/programs/nix-index.nix +++ b/modules/programs/nix-index.nix @@ -41,7 +41,7 @@ in { source ${cfg.package}/etc/profile.d/command-not-found.sh ''; - programs.zsh.initExtra = lib.mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = lib.mkIf cfg.enableZshIntegration '' source ${cfg.package}/etc/profile.d/command-not-found.sh ''; diff --git a/modules/programs/nix-your-shell.nix b/modules/programs/nix-your-shell.nix index adace4e15..c39d3a501 100644 --- a/modules/programs/nix-your-shell.nix +++ b/modules/programs/nix-your-shell.nix @@ -45,7 +45,7 @@ in { ''; }; - zsh.initExtra = mkIf cfg.enableZshIntegration '' + zsh.initContent = mkIf cfg.enableZshIntegration '' ${cfg.package}/bin/nix-your-shell zsh | source /dev/stdin ''; }; diff --git a/modules/programs/notmuch.nix b/modules/programs/notmuch.nix index a3d679b23..071f08558 100644 --- a/modules/programs/notmuch.nix +++ b/modules/programs/notmuch.nix @@ -37,8 +37,9 @@ let in { name = catAttrs "realName" primary; primary_email = catAttrs "address" primary; - other_email = catAttrs "aliases" primary ++ catAttrs "address" secondaries - ++ catAttrs "aliases" secondaries; + other_email = map (email: email.address or email) (flatten + (catAttrs "aliases" primary ++ catAttrs "address" secondaries + ++ catAttrs "aliases" secondaries)); }; search = { exclude_tags = cfg.search.excludeTags; }; diff --git a/modules/programs/nushell.nix b/modules/programs/nushell.nix index a4e767c8a..f18f6abff 100644 --- a/modules/programs/nushell.nix +++ b/modules/programs/nushell.nix @@ -46,7 +46,7 @@ in { options.programs.nushell = { enable = lib.mkEnableOption "nushell"; - package = lib.mkPackageOption pkgs "nushell" { }; + package = lib.mkPackageOption pkgs "nushell" { nullable = true; }; configFile = lib.mkOption { type = types.nullOr (linesOrSource "config.nu"); @@ -197,7 +197,13 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [ cfg.package ]; + warnings = lib.optional (cfg.package == null && cfg.plugins != [ ]) '' + You have configured `plugins` for `nushell` but have not set `package`. + + The listed plugins will not be installed. + ''; + + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file = lib.mkMerge [ (let @@ -261,7 +267,7 @@ in { (map (plugin: "plugin add ${lib.getExe plugin}") cfg.plugins) }' ''; - in lib.mkIf (cfg.plugins != [ ]) { + in lib.mkIf ((cfg.package != null) && (cfg.plugins != [ ])) { "${configDir}/plugin.msgpackz".source = "${msgPackz}/plugin.msgpackz"; }) ]; diff --git a/modules/programs/oh-my-posh.nix b/modules/programs/oh-my-posh.nix index be406e662..dc666afb0 100644 --- a/modules/programs/oh-my-posh.nix +++ b/modules/programs/oh-my-posh.nix @@ -71,7 +71,7 @@ in { eval "$(${cfg.package}/bin/oh-my-posh init bash ${configArgument})" ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' eval "$(${cfg.package}/bin/oh-my-posh init zsh ${configArgument})" ''; diff --git a/modules/programs/onlyoffice.nix b/modules/programs/onlyoffice.nix new file mode 100644 index 000000000..a279af944 --- /dev/null +++ b/modules/programs/onlyoffice.nix @@ -0,0 +1,50 @@ +{ lib, pkgs, config, ... }: + +let + inherit (lib) + types isBool boolToString concatStringsSep mapAttrsToList mkIf + mkEnableOption mkPackageOption mkOption; + + cfg = config.programs.onlyoffice; + + attrToString = name: value: + let newvalue = if (isBool value) then (boolToString value) else value; + in "${name}=${newvalue}"; + + getFinalConfig = set: + (concatStringsSep "\n" (mapAttrsToList attrToString set)) + "\n"; +in { + meta.maintainers = with lib.hm.maintainers; [ aguirre-matteo ]; + + options.programs.onlyoffice = { + enable = mkEnableOption "onlyoffice"; + + package = + mkPackageOption pkgs "onlyoffice-desktopeditors" { nullable = true; }; + + settings = mkOption { + type = with types; attrsOf (either bool str); + default = { }; + example = '' + UITheme = "theme-contrast-dark"; + editorWindowMode = false; + forcedRtl = false; + maximized = true; + titlebar = "custom"; + ''; + description = '' + Configuration settings for Onlyoffice. + + All configurable options can be deduced by enabling them through the + GUI and observing the changes in ~/.config/onlyoffice/DesktopEditors.conf. + ''; + }; + }; + + config = mkIf cfg.enable { + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + + xdg.configFile."onlyoffice/DesktopEditors.conf".source = + pkgs.writeText "DesktopEditors.conf" (getFinalConfig cfg.settings); + }; +} diff --git a/modules/programs/opam.nix b/modules/programs/opam.nix index 6027737cd..f71dd4179 100644 --- a/modules/programs/opam.nix +++ b/modules/programs/opam.nix @@ -36,7 +36,7 @@ in { eval "$(${cfg.package}/bin/opam env --shell=bash)" ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' eval "$(${cfg.package}/bin/opam env --shell=zsh)" ''; diff --git a/modules/programs/openstackclient.nix b/modules/programs/openstackclient.nix index 98d68a2f2..c7ee7d636 100644 --- a/modules/programs/openstackclient.nix +++ b/modules/programs/openstackclient.nix @@ -9,7 +9,7 @@ in { options.programs.openstackclient = { enable = lib.mkEnableOption "OpenStack command-line client"; - package = lib.mkPackageOption pkgs "openstackclient" { }; + package = lib.mkPackageOption pkgs "openstackclient" { nullable = true; }; clouds = lib.mkOption { type = lib.types.submodule { freeformType = yamlFormat.type; }; @@ -58,7 +58,7 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."openstack/clouds.yaml".source = yamlFormat.generate "openstackclient-clouds-yaml-${config.home.username}" { diff --git a/modules/programs/papis.nix b/modules/programs/papis.nix index 837bfc274..1b8ae1377 100644 --- a/modules/programs/papis.nix +++ b/modules/programs/papis.nix @@ -19,7 +19,7 @@ in { options.programs.papis = { enable = mkEnableOption "papis"; - package = mkPackageOption pkgs "papis" { }; + package = mkPackageOption pkgs "papis" { nullable = true; }; settings = mkOption { type = with types; attrsOf (oneOf [ bool int str ]); @@ -86,7 +86,7 @@ in { (", namely " + concatStringsSep "," defaultLibraries); }]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."papis/config" = mkIf (cfg.libraries != { }) { text = generators.toINI { } settingsIni; }; diff --git a/modules/programs/pay-respects.nix b/modules/programs/pay-respects.nix index 8802ad25e..302d1b125 100644 --- a/modules/programs/pay-respects.nix +++ b/modules/programs/pay-respects.nix @@ -35,7 +35,7 @@ in { ''} ''; - zsh.initExtra = '' + zsh.initContent = '' ${optionalString cfg.enableZshIntegration '' eval "$(${payRespectsCmd} zsh --alias)" ''} diff --git a/modules/programs/pazi.nix b/modules/programs/pazi.nix index 848dfa309..8e9838aff 100644 --- a/modules/programs/pazi.nix +++ b/modules/programs/pazi.nix @@ -29,7 +29,7 @@ in { eval "$(${pkgs.pazi}/bin/pazi init bash)" ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' eval "$(${pkgs.pazi}/bin/pazi init zsh)" ''; diff --git a/modules/programs/poetry.nix b/modules/programs/poetry.nix index d297f0c78..54fa2abb3 100644 --- a/modules/programs/poetry.nix +++ b/modules/programs/poetry.nix @@ -20,6 +20,7 @@ in { enable = mkEnableOption "poetry"; package = mkPackageOption pkgs "poetry" { + nullable = true; example = "pkgs.poetry.withPlugins (ps: with ps; [ poetry-plugin-up ])"; extraDescription = "May be used to install custom poetry plugins."; }; @@ -45,7 +46,7 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file."${configDir}/pypoetry/config.toml" = lib.mkIf (cfg.settings != { }) { diff --git a/modules/programs/powerline-go.nix b/modules/programs/powerline-go.nix index 9bc9491b6..520229c12 100644 --- a/modules/programs/powerline-go.nix +++ b/modules/programs/powerline-go.nix @@ -142,27 +142,28 @@ in { fi ''; - programs.zsh.initExtra = mkIf (cfg.enable && config.programs.zsh.enable) '' - function powerline_precmd() { - ${ - if evalMode then "eval " else "PS1=" - }"$(${pkgs.powerline-go}/bin/powerline-go -error $? -shell zsh${commandLineArguments})" - ${cfg.extraUpdatePS1} - } + programs.zsh.initContent = + mkIf (cfg.enable && config.programs.zsh.enable) '' + function powerline_precmd() { + ${ + if evalMode then "eval " else "PS1=" + }"$(${pkgs.powerline-go}/bin/powerline-go -error $? -shell zsh${commandLineArguments})" + ${cfg.extraUpdatePS1} + } - function install_powerline_precmd() { - for s in "$\{precmd_functions[@]}"; do - if [ "$s" = "powerline_precmd" ]; then - return - fi - done - precmd_functions+=(powerline_precmd) - } + function install_powerline_precmd() { + for s in "$\{precmd_functions[@]}"; do + if [ "$s" = "powerline_precmd" ]; then + return + fi + done + precmd_functions+=(powerline_precmd) + } - if [ "$TERM" != "linux" ]; then - install_powerline_precmd - fi - ''; + if [ "$TERM" != "linux" ]; then + install_powerline_precmd + fi + ''; # https://github.com/justjanne/powerline-go#fish programs.fish.interactiveShellInit = diff --git a/modules/programs/pyenv.nix b/modules/programs/pyenv.nix index 1ff1f2832..e18c7a924 100644 --- a/modules/programs/pyenv.nix +++ b/modules/programs/pyenv.nix @@ -54,7 +54,7 @@ in { eval "$(${lib.getExe cfg.package} init - bash)" ''; - programs.zsh.initExtra = lib.mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = lib.mkIf cfg.enableZshIntegration '' export PYENV_ROOT="${cfg.rootDirectory}" eval "$(${lib.getExe cfg.package} init - zsh)" ''; diff --git a/modules/programs/pywal.nix b/modules/programs/pywal.nix index b32f087c3..c29ece0e9 100644 --- a/modules/programs/pywal.nix +++ b/modules/programs/pywal.nix @@ -11,7 +11,7 @@ in { home.packages = [ pkgs.pywal ]; - programs.zsh.initExtra = '' + programs.zsh.initContent = '' # Import colorscheme from 'wal' asynchronously # & # Run the process in the background. # ( ) # Hide shell job control messages. diff --git a/modules/programs/rbenv.nix b/modules/programs/rbenv.nix index 11b48abf4..59b9bba76 100644 --- a/modules/programs/rbenv.nix +++ b/modules/programs/rbenv.nix @@ -79,7 +79,7 @@ in { eval "$(${cfg.package}/bin/rbenv init - bash)" ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' eval "$(${cfg.package}/bin/rbenv init - zsh)" ''; diff --git a/modules/programs/rclone.nix b/modules/programs/rclone.nix new file mode 100644 index 000000000..7d0b87315 --- /dev/null +++ b/modules/programs/rclone.nix @@ -0,0 +1,151 @@ +{ config, lib, pkgs, ... }: + +let + + cfg = config.programs.rclone; + iniFormat = pkgs.formats.ini { }; + +in { + options = { + programs.rclone = { + enable = lib.mkEnableOption "rclone"; + + package = lib.mkPackageOption pkgs "rclone" { }; + + remotes = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule { + options = { + config = lib.mkOption { + type = with lib.types; + let + baseType = attrsOf (nullOr (oneOf [ bool int float str ])); + + # Should we verify whether type constitutes a valid remote? + remoteConfigType = addCheck baseType (lib.hasAttr "type") // { + name = "rcloneRemoteConfig"; + description = + "An attribute set containing a remote type and options."; + }; + in remoteConfigType; + default = { }; + description = '' + Regular configuration options as described in rclone's documentation + . When specifying options follow the formatting + process outlined here , namley: + - Remove the leading double-dash (--) from the rclone option name + - Replace hyphens (-) with underscores (_) + - Convert to lowercase + - Use the resulting string as your configuration key + + For example, the rclone option "--mega-hard-delete" would use "hard_delete" + as the config key. + + Security Note: Always use the {option}`secrets` option for sensitive data + instead of the {option}`config` option to prevent exposing credentials to + the world-readable Nix store. + ''; + example = lib.literalExpression '' + { + type = "mega"; # Required - specifies the remote type + user = "you@example.com"; + hard_delete = true; + }''; + }; + + secrets = lib.mkOption { + type = with lib.types; attrsOf str; + default = { }; + description = '' + Sensitive configuration values such as passwords, API keys, and tokens. These + must be provided as file paths to the secrets, which will be read at activation + time. + + Note: If using secret management solutions like agenix or sops-nix with + home-manager, you need to ensure their services are activated before switching + to this home-manager generation. Consider setting + {option}`systemd.user.startServices` to `"sd-switch"` for automatic service + startup. + ''; + example = lib.literalExpression '' + { + password = "/run/secrets/password"; + api_key = config.age.secrets.api-key.path; + }''; + }; + }; + }); + default = { }; + description = '' + An attribute set of remote configurations. Each remote consists of regular + configuration options and optional secrets. + + See for more information on configuring specific + remotes. + ''; + example = lib.literalExpression '' + { + b2 = { + config = { + type = "b2"; + hard_delete = true; + }; + secrets = { + # using sops + account = config.sops.secrets.b2-acc-id.path; + # using agenix + key = config.age.secrets.b2-key.path; + }; + }; + + server.config = { + type = "sftp"; + host = "server"; + user = "backup"; + key_file = "''${home.homeDirectory}/.ssh/id_ed25519"; + }; + }''; + }; + + writeAfter = lib.mkOption { + type = lib.types.str; + default = "reloadSystemd"; + description = '' + Controls when the rclone configuration is written during Home Manager activation. + You should not need to change this unless you have very specific activation order + requirements. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + home = { + packages = [ cfg.package ]; + + activation.createRcloneConfig = let + safeConfig = lib.pipe cfg.remotes [ + (lib.mapAttrs (_: v: v.config)) + (iniFormat.generate "rclone.conf@pre-secrets") + ]; + + # https://github.com/rclone/rclone/issues/8190 + injectSecret = remote: + lib.mapAttrsToList (secret: secretFile: '' + ${lib.getExe cfg.package} config update \ + ${remote.name} config_refresh_token=false \ + ${secret} "$(cat ${secretFile})" \ + --quiet > /dev/null + '') remote.value.secrets or { }; + + injectAllSecrets = lib.concatMap injectSecret + (lib.mapAttrsToList lib.nameValuePair cfg.remotes); + in lib.mkIf (cfg.remotes != { }) + (lib.hm.dag.entryAfter [ "writeBoundary" cfg.writeAfter ] '' + run install $VERBOSE_ARG -D -m600 ${safeConfig} "${config.xdg.configHome}/rclone/rclone.conf" + ${lib.concatLines injectAllSecrets} + ''); + }; + }; + + meta.maintainers = with lib.hm.maintainers; [ jess ]; +} diff --git a/modules/programs/rio.nix b/modules/programs/rio.nix index 5a5ce6fa3..927cb406b 100644 --- a/modules/programs/rio.nix +++ b/modules/programs/rio.nix @@ -12,7 +12,7 @@ in { ''; }; - package = lib.mkPackageOption pkgs "rio" { }; + package = lib.mkPackageOption pkgs "rio" { nullable = true; }; settings = lib.mkOption { type = settingsFormat.type; @@ -27,7 +27,7 @@ in { config = lib.mkIf cfg.enable (lib.mkMerge [ { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; } # Only manage configuration if not empty diff --git a/modules/programs/ripgrep-all.nix b/modules/programs/ripgrep-all.nix new file mode 100644 index 000000000..cef0de21b --- /dev/null +++ b/modules/programs/ripgrep-all.nix @@ -0,0 +1,102 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.programs.ripgrep-all; + configPath = if pkgs.stdenv.hostPlatform.isDarwin then + "Library/Application Support/ripgrep-all/config.jsonc" + else + "${config.xdg.configHome}/ripgrep-all/config.jsonc"; + customAdapter = lib.types.submodule { + # Descriptions are largely copied from https://github.com/phiresky/ripgrep-all/blob/v1.0.0-alpha.5/src/adapters/custom.rs + options = { + name = lib.mkOption { + type = lib.types.str; + description = + "The unique identifier and name of this adapter; must only include a-z, 0-9, _"; + }; + version = lib.mkOption { + type = lib.types.int; + default = 1; + description = + "The version identifier used to key cache entries; change if the configuration or program changes"; + }; + description = lib.mkOption { + type = lib.types.str; + description = "A description of this adapter; shown in rga's help"; + }; + extensions = lib.mkOption { + type = with lib.types; listOf str; + description = "The file extensions this adapter supports"; + example = [ "pdf" ]; + }; + mimetypes = lib.mkOption { + type = with lib.types; nullOr (listOf str); + default = null; + description = + "If not null and --rga-accurate is enabled, mime type matching is used instead of file name matching"; + example = [ "application/pdf" ]; + }; + binary = lib.mkOption { + type = lib.types.path; + description = "The path of the binary to run"; + }; + args = lib.mkOption { + type = with lib.types; listOf str; + default = [ ]; + description = + "The output path hint; the placeholders are the same as for rga's `args`"; + }; + disabled_by_default = lib.mkOption { + type = with lib.types; nullOr bool; + default = null; + description = "If true, the adapter will be disabled by default"; + }; + match_only_by_mime = lib.mkOption { + type = with lib.types; nullOr bool; + default = null; + description = + "if --rga-accurate, only match by mime types, ignore extensions completely"; + }; + output_path_hint = lib.mkOption { + type = with lib.types; nullOr str; + default = null; + description = + "Setting this is useful if the output format is not plain text (.txt) but instead some other format that should be passed to another adapter"; + example = "$${input_virtual_path}.txt.asciipagebreaks"; + }; + }; + }; +in { + meta.maintainers = with lib.maintainers; [ lafrenierejm ]; + + options = { + programs.ripgrep-all = { + enable = lib.mkEnableOption "ripgrep-all (rga)"; + + package = lib.mkPackageOption pkgs "ripgrep-all" { nullable = true; }; + + custom_adapters = lib.mkOption { + type = lib.types.listOf customAdapter; + default = [ ]; + description = '' + Custom adapters that invoke external preprocessing scripts. + See . + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + home = { + packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + + file."${configPath}" = lib.mkIf (cfg.custom_adapters != [ ]) { + source = (pkgs.formats.json { }).generate "ripgrep-all" { + "$schema" = "./config.schema.json"; + custom_adapters = + map (lib.filterAttrs (n: v: v != null)) cfg.custom_adapters; + }; + }; + }; + }; +} diff --git a/modules/programs/ripgrep.nix b/modules/programs/ripgrep.nix index 58faa520a..3154a770d 100644 --- a/modules/programs/ripgrep.nix +++ b/modules/programs/ripgrep.nix @@ -2,9 +2,7 @@ with lib; -let - cfg = config.programs.ripgrep; - configPath = "${config.xdg.configHome}/ripgrep/ripgreprc"; +let cfg = config.programs.ripgrep; in { meta.maintainers = [ lib.maintainers.khaneliman lib.hm.maintainers.pedorich-n ]; @@ -13,7 +11,7 @@ in { programs.ripgrep = { enable = mkEnableOption "Ripgrep"; - package = mkPackageOption pkgs "ripgrep" { }; + package = mkPackageOption pkgs "ripgrep" { nullable = true; }; arguments = mkOption { type = with types; listOf str; @@ -31,8 +29,9 @@ in { }; config = mkIf cfg.enable { - home = mkMerge [ - { packages = [ cfg.package ]; } + home = let configPath = "${config.xdg.configHome}/ripgrep/ripgreprc"; + in mkMerge [ + { packages = lib.mkIf (cfg.package != null) [ cfg.package ]; } (mkIf (cfg.arguments != [ ]) { file."${configPath}".text = lib.concatLines cfg.arguments; diff --git a/modules/programs/rofi-pass.nix b/modules/programs/rofi-pass.nix index f1de580fb..d5208d504 100644 --- a/modules/programs/rofi-pass.nix +++ b/modules/programs/rofi-pass.nix @@ -12,8 +12,10 @@ in { options.programs.rofi.pass = { enable = mkEnableOption "rofi integration with password-store"; - package = - mkPackageOption pkgs "rofi-pass" { example = "pkgs.rofi-pass-wayland"; }; + package = mkPackageOption pkgs "rofi-pass" { + nullable = true; + example = "pkgs.rofi-pass-wayland"; + }; stores = mkOption { type = types.listOf types.str; @@ -40,7 +42,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."rofi-pass/config".text = optionalString (cfg.stores != [ ]) ("root=" + (concatStringsSep ":" cfg.stores) + "\n") + cfg.extraConfig diff --git a/modules/programs/ruff.nix b/modules/programs/ruff.nix index e1490089a..4ae80ebda 100644 --- a/modules/programs/ruff.nix +++ b/modules/programs/ruff.nix @@ -15,7 +15,7 @@ in { enable = mkEnableOption "ruff, an extremely fast Python linter and code formatter, written in Rust"; - package = mkPackageOption pkgs "ruff" { }; + package = mkPackageOption pkgs "ruff" { nullable = true; }; settings = mkOption { type = settingsFormat.type; @@ -37,7 +37,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."ruff/ruff.toml".source = settingsFormat.generate "ruff.toml" cfg.settings; diff --git a/modules/programs/sagemath.nix b/modules/programs/sagemath.nix index 70efaca56..7d34adc49 100644 --- a/modules/programs/sagemath.nix +++ b/modules/programs/sagemath.nix @@ -12,11 +12,11 @@ in { options.programs.sagemath = { enable = mkEnableOption "SageMath, a mathematics software system"; - package = mkOption { - type = types.package; - default = pkgs.sage; - defaultText = literalExpression "pkgs.sage"; - description = "The SageMath package to use."; + package = lib.mkPackageOption pkgs "sage" { + nullable = true; + extraDescription = '' + The SageMath package to use. + ''; }; configDir = mkOption { @@ -52,9 +52,10 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file."${cfg.configDir}/init.sage".text = cfg.initScript; + home.sessionVariables = { DOT_SAGE = cfg.dataDir; SAGE_STARTUP_FILE = "${cfg.configDir}/init.sage"; diff --git a/modules/programs/sapling.nix b/modules/programs/sapling.nix index d2a4b4319..4e27aaa82 100644 --- a/modules/programs/sapling.nix +++ b/modules/programs/sapling.nix @@ -15,7 +15,7 @@ in { programs.sapling = { enable = mkEnableOption "Sapling"; - package = mkPackageOption pkgs "sapling" { }; + package = mkPackageOption pkgs "sapling" { nullable = true; }; userName = mkOption { type = types.str; @@ -48,7 +48,7 @@ in { config = mkIf cfg.enable (mkMerge [ { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; programs.sapling.iniContent.ui = { username = cfg.userName + " <" + cfg.userEmail + ">"; diff --git a/modules/programs/scmpuff.nix b/modules/programs/scmpuff.nix index f9ff922a9..33642a359 100644 --- a/modules/programs/scmpuff.nix +++ b/modules/programs/scmpuff.nix @@ -45,7 +45,7 @@ in { eval "$(${cfg.package}/bin/scmpuff init ${mkArgs "bash"})" ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' eval "$(${cfg.package}/bin/scmpuff init ${mkArgs "zsh"})" ''; diff --git a/modules/programs/sftpman.nix b/modules/programs/sftpman.nix index c6978f80a..3a8ba5ee6 100644 --- a/modules/programs/sftpman.nix +++ b/modules/programs/sftpman.nix @@ -73,7 +73,7 @@ in { enable = mkEnableOption "sftpman, an application that handles sshfs/sftp file systems mounting"; - package = mkPackageOption pkgs "sftpman" { }; + package = mkPackageOption pkgs "sftpman" { nullable = true; }; defaultSshKey = mkOption { type = types.nullOr types.str; @@ -107,7 +107,7 @@ in { }) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile = mapAttrs' (name: value: nameValuePair "sftpman/mounts/${name}.json" { diff --git a/modules/programs/skim.nix b/modules/programs/skim.nix index 0f47a00bf..4c2215489 100644 --- a/modules/programs/skim.nix +++ b/modules/programs/skim.nix @@ -114,7 +114,7 @@ in { fi ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' if [[ $options[zle] = on ]]; then . ${cfg.package}/share/skim/completion.zsh . ${cfg.package}/share/skim/key-bindings.zsh diff --git a/modules/programs/sm64ex.nix b/modules/programs/sm64ex.nix index 23b75808f..a005484c2 100644 --- a/modules/programs/sm64ex.nix +++ b/modules/programs/sm64ex.nix @@ -34,11 +34,7 @@ in { options.programs.sm64ex = { enable = mkEnableOption "sm64ex"; - package = mkOption { - type = types.package; - default = pkgs.sm64ex; - description = "The sm64ex package to use."; - }; + package = lib.mkPackageOption pkgs "sm64ex" { nullable = true; }; region = mkOption { type = types.nullOr (types.enum [ "us" "eu" "jp" ]); @@ -120,7 +116,7 @@ in { configFile = optionals (cfg.settings != null) (concatStringsSep "\n" ((mapAttrsToList mkConfig cfg.settings))); in mkIf cfg.enable { - home.packages = [ package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.dataFile."sm64pc/sm64config.txt" = mkIf (cfg.settings != null) { text = configFile; }; diff --git a/modules/programs/spotify-player.nix b/modules/programs/spotify-player.nix index 35d3933bc..bc401fda6 100644 --- a/modules/programs/spotify-player.nix +++ b/modules/programs/spotify-player.nix @@ -13,7 +13,7 @@ in { options.programs.spotify-player = { enable = mkEnableOption "spotify-player"; - package = mkPackageOption pkgs "spotify-player" { }; + package = mkPackageOption pkgs "spotify-player" { nullable = true; }; settings = mkOption { type = tomlType; @@ -162,7 +162,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile = { "spotify-player/app.toml" = mkIf (cfg.settings != { }) { diff --git a/modules/programs/starship.nix b/modules/programs/starship.nix index fb0b97d69..1874b0ef7 100644 --- a/modules/programs/starship.nix +++ b/modules/programs/starship.nix @@ -110,7 +110,7 @@ in { fi ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' if [[ $TERM != "dumb" ]]; then eval "$(${starshipCmd} init zsh)" fi diff --git a/modules/programs/swayimg.nix b/modules/programs/swayimg.nix new file mode 100644 index 000000000..aac56ece3 --- /dev/null +++ b/modules/programs/swayimg.nix @@ -0,0 +1,53 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.programs.swayimg; + iniFormat = pkgs.formats.ini { }; +in { + meta.maintainers = with lib.maintainers; [ dod-101 ]; + + options.programs.swayimg = { + enable = lib.mkEnableOption "swayimg"; + package = lib.mkOption { + type = lib.types.package; + default = pkgs.swayimg; + defaultText = lib.literalExpression "pkgs.swayimg"; + description = "The swayimg package to install"; + }; + settings = lib.mkOption { + type = iniFormat.type; + default = { }; + description = '' + Configuration written to + {file}`$XDG_CONFIG_HOME/swayimg/config`. See for a list of available options. + ''; + example = lib.literalExpression '' + { + viewer = { + window = "#10000010"; + scale = "fill"; + }; + "info.viewer" = { + top_left = "+name,+format"; + }; + "keys.viewer" = { + "Shift+r" = "rand_file"; + }; + } + ''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "programs.swayimg" pkgs + lib.platforms.linux) + ]; + + home.packages = [ cfg.package ]; + + xdg.configFile."swayimg/config" = lib.mkIf (cfg.settings != { }) { + source = iniFormat.generate "config" cfg.settings; + }; + }; +} diff --git a/modules/programs/swaylock.nix b/modules/programs/swaylock.nix index be577ea80..dcfd30c7e 100644 --- a/modules/programs/swaylock.nix +++ b/modules/programs/swaylock.nix @@ -33,10 +33,10 @@ in { ''; }; - package = mkPackageOption pkgs "swaylock" { }; + package = mkPackageOption pkgs "swaylock" { nullable = true; }; settings = mkOption { - type = with types; attrsOf (oneOf [ bool float int str ]); + type = with types; attrsOf (oneOf [ bool float int path str ]); default = { }; description = '' Default arguments to {command}`swaylock`. An empty set @@ -59,7 +59,7 @@ in { lib.platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."swaylock/config" = mkIf (cfg.settings != { }) { text = concatStrings (mapAttrsToList (n: v: diff --git a/modules/programs/taskwarrior.nix b/modules/programs/taskwarrior.nix index 9b5af43ee..8efeb1366 100644 --- a/modules/programs/taskwarrior.nix +++ b/modules/programs/taskwarrior.nix @@ -23,9 +23,6 @@ let formatPair = key: value: if isAttrs value then formatSet key value else formatLine key value; - - homeConf = "${config.xdg.configHome}/task/home-manager-taskrc"; - userConf = "${config.xdg.configHome}/task/taskrc"; in { options = { programs.taskwarrior = { @@ -85,13 +82,18 @@ in { ''; }; - package = - mkPackageOption pkgs "taskwarrior" { example = "pkgs.taskwarrior3"; }; + package = mkPackageOption pkgs "taskwarrior" { + nullable = true; + example = "pkgs.taskwarrior3"; + }; }; }; - config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + config = let + homeConf = "${config.xdg.configHome}/task/home-manager-taskrc"; + userConf = "${config.xdg.configHome}/task/taskrc"; + in mkIf cfg.enable { + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file."${homeConf}".text = '' data.location=${cfg.dataLocation} diff --git a/modules/programs/tex-fmt.nix b/modules/programs/tex-fmt.nix new file mode 100644 index 000000000..94e3fe4bc --- /dev/null +++ b/modules/programs/tex-fmt.nix @@ -0,0 +1,53 @@ +{ pkgs, config, lib, ... }: + +let + + inherit (lib) mkEnableOption mkPackageOption mkOption literalExpression; + + configDir = if pkgs.stdenv.isDarwin then + "Library/Application Support" + else + config.xdg.configHome; + + tomlFormat = pkgs.formats.toml { }; + cfg = config.programs.tex-fmt; + +in { + meta.maintainers = with lib.maintainers; [ mirkolenz wgunderwood ]; + + options.programs.tex-fmt = { + enable = mkEnableOption "tex-fmt"; + + package = mkPackageOption pkgs "tex-fmt" { nullable = true; }; + + settings = mkOption { + type = tomlFormat.type; + default = { }; + example = literalExpression '' + { + wrap = true; + tabsize = 2; + tabchar = "space"; + lists = []; + } + ''; + description = '' + Configuration written to + {file}`$XDG_CONFIG_HOME/tex-fmt/tex-fmt.toml` on Linux or + {file}`$HOME/Library/Application Support/tex-fmt/tex-fmt.toml` on Darwin. + See and + + for more information. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + + home.file."${configDir}/tex-fmt/tex-fmt.toml" = + lib.mkIf (cfg.settings != { }) { + source = tomlFormat.generate "tex-fmt-config" cfg.settings; + }; + }; +} diff --git a/modules/programs/thefuck.nix b/modules/programs/thefuck.nix index 1a5574921..ac1eb6348 100644 --- a/modules/programs/thefuck.nix +++ b/modules/programs/thefuck.nix @@ -57,7 +57,7 @@ with lib; }; }; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration shEvalCmd; + programs.zsh.initContent = mkIf cfg.enableZshIntegration shEvalCmd; programs.nushell = mkIf cfg.enableNushellIntegration { extraConfig = '' diff --git a/modules/programs/thunderbird.nix b/modules/programs/thunderbird.nix index 84710207c..d567ab44f 100644 --- a/modules/programs/thunderbird.nix +++ b/modules/programs/thunderbird.nix @@ -49,16 +49,25 @@ let }; })); + getId = account: address: + if address == account.address then + account.id + else + (builtins.hashString "sha256" (if (builtins.isString address) then + address + else + (address.address + address.realName))); + toThunderbirdIdentity = account: address: # For backwards compatibility, the primary address reuses the account ID. let - id = if address == account.address then - account.id - else - builtins.hashString "sha256" address; + id = getId account address; + addressIsString = builtins.isString address; in { - "mail.identity.id_${id}.fullName" = account.realName; - "mail.identity.id_${id}.useremail" = address; + "mail.identity.id_${id}.fullName" = + if addressIsString then account.realName else address.realName; + "mail.identity.id_${id}.useremail" = + if addressIsString then address else address.address; "mail.identity.id_${id}.valid" = true; "mail.identity.id_${id}.htmlSigText" = if account.signature.showSignature == "none" then @@ -87,9 +96,7 @@ let addresses = [ account.address ] ++ account.aliases; in { "mail.account.account_${id}.identities" = concatStringsSep "," - ([ "id_${id}" ] - ++ map (address: "id_${builtins.hashString "sha256" address}") - account.aliases); + (map (address: "id_${getId account address}") addresses); "mail.account.account_${id}.server" = "server_${id}"; } // optionalAttrs account.primary { "mail.accountmanager.defaultaccount" = "account_${id}"; @@ -128,6 +135,18 @@ let (builtins.map (address: toThunderbirdIdentity account address) addresses) // account.thunderbird.settings id; + toThunderbirdFeed = feed: profile: + let id = feed.id; + in { + "mail.account.account_${id}.server" = "server_${id}"; + "mail.server.server_${id}.name" = feed.name; + "mail.server.server_${id}.type" = "rss"; + "mail.server.server_${id}.directory" = + "${thunderbirdProfilesPath}/${profile.name}/Mail/Feeds-${id}"; + "mail.server.server_${id}.directory-rel" = "[ProfD]Mail/Feeds-${id}"; + "mail.server.server_${id}.hostname" = "Feeds-${id}"; + }; + mkUserJs = prefs: extraPrefs: '' // Generated by Home Manager. @@ -136,6 +155,32 @@ let '') prefs)} ${extraPrefs} ''; + + mkFilterToIniString = f: + if f.text == null then + '' + name="${f.name}" + enabled="${if f.enabled then "yes" else "no"}" + type="${f.type}" + action="${f.action}" + '' + optionalString (f.actionValue != null) '' + actionValue="${f.actionValue}" + '' + '' + condition="${f.condition}" + '' + optionalString (f.extraConfig != null) f.extraConfig + else + f.text; + + mkFilterListToIni = filters: + '' + version="9" + logging="no" + '' + concatStrings (map (f: mkFilterToIniString f) filters); + + getEmailAccountsForProfile = profileName: accounts: + (filter (a: + a.thunderbird.profiles == [ ] + || any (p: p == profileName) a.thunderbird.profiles) accounts); in { meta.maintainers = with hm.maintainers; [ d-dervishi jkarlson ]; @@ -158,6 +203,16 @@ in { description = "profile version, set null for nix-darwin"; }; + nativeMessagingHosts = mkOption { + visible = true; + type = types.listOf types.package; + default = [ ]; + description = '' + Additional packages containing native messaging hosts that should be + made available to Thunderbird extensions. + ''; + }; + profiles = mkOption { type = with types; attrsOf (submodule ({ config, name, ... }: { @@ -179,6 +234,25 @@ in { ''; }; + feedAccounts = mkOption { + type = types.attrsOf (submodule ({ config, name, ... }: { + options = { + name = mkOption { + type = types.str; + default = name; + readOnly = true; + description = "This feed account's name."; + }; + }; + })); + default = { }; + description = '' + Attribute set of feed accounts. Feeds themselves have to be + managed through Thunderbird's settings. This option allows + feeds to coexist with declaratively managed email accounts. + ''; + }; + settings = mkOption { type = thunderbirdJson; default = { }; @@ -310,7 +384,19 @@ in { accounts.email.accounts = mkOption { type = with types; - attrsOf (submodule { + attrsOf (submodule ({ config, ... }: { + config.thunderbird = { + settings = lib.mkIf (config.flavor == "gmail.com") (id: { + "mail.smtpserver.smtp_${id}.authMethod" = + mkOptionDefault 10; # 10 = OAuth2 + "mail.server.server_${id}.authMethod" = + mkOptionDefault 10; # 10 = OAuth2 + "mail.server.server_${id}.socketType" = + mkOptionDefault 3; # SSL/TLS + "mail.server.server_${id}.is_gmail" = + mkOptionDefault true; # handle labels, trash, etc + }); + }; options.thunderbird = { enable = mkEnableOption "the Thunderbird mail client for this account"; @@ -360,8 +446,73 @@ in { argument is an automatically generated identifier. ''; }; + + messageFilters = mkOption { + type = with types; + listOf (submodule { + options = { + name = mkOption { + type = str; + description = "Name for the filter."; + }; + enabled = mkOption { + type = bool; + default = true; + description = "Whether this filter is currently active."; + }; + type = mkOption { + type = str; + description = "Type for this filter."; + }; + action = mkOption { + type = str; + description = "Action to perform on matched messages."; + }; + actionValue = mkOption { + type = nullOr str; + default = null; + description = + "Argument passed to the filter action, e.g. a folder path."; + }; + condition = mkOption { + type = str; + description = "Condition to match messages against."; + }; + extraConfig = mkOption { + type = nullOr str; + default = null; + description = "Extra settings to apply to the filter"; + }; + text = mkOption { + type = nullOr str; + default = null; + description = '' + The raw text of the filter. + Note that this will override all other options. + ''; + }; + }; + }); + default = [ ]; + defaultText = literalExpression "[ ]"; + example = literalExpression '' + [ + { + name = "Mark as Read on Archive"; + enabled = true; + type = "128"; + action = "Mark read"; + condition = "ALL"; + } + ] + ''; + description = '' + List of message filters to add to this Thunderbird account + configuration. + ''; + }; }; - }); + })); }; }; @@ -400,6 +551,10 @@ in { ++ optional (any (p: p.withExternalGnupg) (attrValues cfg.profiles)) pkgs.gpgme; + mozilla.thunderbirdNativeMessagingHosts = [ + cfg.package # package configured native messaging hosts (entire mail app actually) + ] ++ cfg.nativeMessagingHosts; # user configured native messaging hosts + home.file = mkMerge ([{ "${thunderbirdConfigPath}/profiles.ini" = mkIf (cfg.profiles != { }) { text = generators.toINI { } profilesIni; }; @@ -411,11 +566,15 @@ in { mkIf (profile.userContent != "") { text = profile.userContent; }; "${thunderbirdProfilesPath}/${name}/user.js" = let - accounts = filter (a: - a.thunderbird.profiles == [ ] - || any (p: p == name) a.thunderbird.profiles) enabledAccountsWithId; + emailAccounts = getEmailAccountsForProfile name enabledAccountsWithId; - smtp = filter (a: a.smtp != null) accounts; + smtp = filter (a: a.smtp != null) emailAccounts; + + feedAccounts = + map (f: f // { id = builtins.hashString "sha256" f.name; }) + (attrValues profile.feedAccounts); + + accounts = emailAccounts ++ feedAccounts; in { text = mkUserJs (builtins.foldl' (a: b: a // b) { } ([ cfg.settings @@ -433,7 +592,8 @@ in { { "mail.openpgp.allow_external_gnupg" = profile.withExternalGnupg; } profile.settings - ] ++ (map (a: toThunderbirdAccount a profile) accounts))) + ] ++ (map (a: toThunderbirdAccount a profile) emailAccounts) + ++ (map (f: toThunderbirdFeed f profile) feedAccounts))) profile.extraConfig; }; @@ -455,6 +615,15 @@ in { recursive = true; force = true; }; - })); + }) ++ (mapAttrsToList (name: profile: + let + emailAccountsWithFilters = + (filter (a: a.thunderbird.messageFilters != [ ]) + (getEmailAccountsForProfile name enabledAccountsWithId)); + in (builtins.listToAttrs (map (a: { + name = + "${thunderbirdProfilesPath}/${name}/ImapMail/${a.id}/msgFilterRules.dat"; + value = { text = mkFilterListToIni a.thunderbird.messageFilters; }; + }) emailAccountsWithFilters))) cfg.profiles)); }; } diff --git a/modules/programs/tmux.nix b/modules/programs/tmux.nix index 85052c9fd..ff3a3322f 100644 --- a/modules/programs/tmux.nix +++ b/modules/programs/tmux.nix @@ -284,7 +284,7 @@ in { shell = mkOption { default = defaultShell; - example = "\${pkgs.zsh}/bin/zsh"; + example = literalExpression "${pkgs.zsh}/bin/zsh"; type = with types; nullOr str; description = "Set the default-shell tmux variable."; }; diff --git a/modules/programs/tofi.nix b/modules/programs/tofi.nix index acc1a994d..b6e46a6cb 100644 --- a/modules/programs/tofi.nix +++ b/modules/programs/tofi.nix @@ -12,7 +12,7 @@ in { options.programs.tofi = { enable = mkEnableOption "Tofi, a tiny dynamic menu for Wayland"; - package = mkPackageOption pkgs "tofi" { }; + package = mkPackageOption pkgs "tofi" { nullable = true; }; settings = mkOption { type = with types; @@ -46,7 +46,7 @@ in { assertions = [ (hm.assertions.assertPlatform "programs.tofi" pkgs platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."tofi/config" = mkIf (cfg.settings != { }) { text = let diff --git a/modules/programs/vifm.nix b/modules/programs/vifm.nix index 2bf31d52d..aef2c1f16 100644 --- a/modules/programs/vifm.nix +++ b/modules/programs/vifm.nix @@ -12,7 +12,7 @@ in { options.programs.vifm = { enable = lib.mkEnableOption "vifm, a Vim-like file manager"; - package = lib.mkPackageOption pkgs "vifm" { }; + package = lib.mkPackageOption pkgs "vifm" { nullable = true; }; extraConfig = mkOption { type = types.lines; @@ -25,7 +25,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."vifm/vifmrc" = mkIf (cfg.extraConfig != "") { text = cfg.extraConfig; }; diff --git a/modules/programs/vim-vint.nix b/modules/programs/vim-vint.nix index 9565a8cb3..655c00937 100644 --- a/modules/programs/vim-vint.nix +++ b/modules/programs/vim-vint.nix @@ -14,7 +14,7 @@ in { options = { programs.vim-vint = { enable = mkEnableOption "the Vint linter for Vimscript"; - package = mkPackageOption pkgs "vim-vint" { }; + package = mkPackageOption pkgs "vim-vint" { nullable = true; }; settings = mkOption { type = yamlFormat.type; @@ -28,7 +28,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile.".vintrc.yaml".source = yamlFormat.generate "vim-vint-config" cfg.settings; diff --git a/modules/programs/vinegar.nix b/modules/programs/vinegar.nix new file mode 100644 index 000000000..cb088d89c --- /dev/null +++ b/modules/programs/vinegar.nix @@ -0,0 +1,50 @@ +{ config, lib, pkgs, ... }: +let toml = pkgs.formats.toml { }; +in { + meta.maintainers = with lib.maintainers; [ HeitorAugustoLN ]; + + options.programs.vinegar = { + enable = lib.mkEnableOption "Vinegar"; + + package = lib.mkPackageOption pkgs "vinegar" { nullable = true; }; + + settings = lib.mkOption { + type = lib.types.attrsOf toml.type; + default = { }; + example = { + env.WINEFSYNC = "1"; + + studio = { + dxvk = false; + renderer = "Vulkan"; + + fflags.DFIntTaskSchedulerTargetFps = 144; + + env = { + DXVK_HUD = "0"; + MANGOHUD = "1"; + }; + }; + }; + description = '' + Configuration written to {file}`$XDG_CONFIG_HOME/vinegar/config.toml`. + + See for more information. + ''; + }; + }; + + config = let cfg = config.programs.vinegar; + in lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "programs.vinegar" pkgs + lib.platforms.linux) + ]; + + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + + xdg.configFile."vinegar/config.toml" = lib.mkIf (cfg.settings != { }) { + source = toml.generate "vinegar-config.toml" cfg.settings; + }; + }; +} diff --git a/modules/programs/vscode.nix b/modules/programs/vscode.nix index fec69aac5..2fee53ac1 100644 --- a/modules/programs/vscode.nix +++ b/modules/programs/vscode.nix @@ -17,6 +17,7 @@ let "vscodium" = "VSCodium"; "openvscode-server" = "OpenVSCode Server"; "windsurf" = "Windsurf"; + "cursor" = "Cursor"; }.${vscodePname}; extensionDir = { @@ -25,6 +26,7 @@ let "vscodium" = "vscode-oss"; "openvscode-server" = "openvscode-server"; "windsurf" = "windsurf"; + "cursor" = "cursor"; }.${vscodePname}; userDir = if pkgs.stdenv.hostPlatform.isDarwin then @@ -32,66 +34,45 @@ let else "${config.xdg.configHome}/${configDir}/User"; - configFilePath = "${userDir}/settings.json"; - tasksFilePath = "${userDir}/tasks.json"; - keybindingsFilePath = "${userDir}/keybindings.json"; + configFilePath = name: + "${userDir}/${ + optionalString (name != "default") "profiles/${name}/" + }settings.json"; + tasksFilePath = name: + "${userDir}/${ + optionalString (name != "default") "profiles/${name}/" + }tasks.json"; + keybindingsFilePath = name: + "${userDir}/${ + optionalString (name != "default") "profiles/${name}/" + }keybindings.json"; - snippetDir = "${userDir}/snippets"; + snippetDir = name: + "${userDir}/${ + optionalString (name != "default") "profiles/${name}/" + }snippets"; # TODO: On Darwin where are the extensions? extensionPath = ".${extensionDir}/extensions"; - extensionJson = pkgs.vscode-utils.toExtensionJson cfg.extensions; - extensionJsonFile = pkgs.writeTextFile { - name = "extensions-json"; - destination = "/share/vscode/extensions/extensions.json"; - text = extensionJson; - }; + extensionJson = ext: pkgs.vscode-utils.toExtensionJson ext; + extensionJsonFile = name: text: + pkgs.writeTextFile { + inherit text; + name = "extensions-json-${name}"; + destination = "/share/vscode/extensions/extensions.json"; + }; - mergedUserSettings = cfg.userSettings - // optionalAttrs (!cfg.enableUpdateCheck) { "update.mode" = "none"; } - // optionalAttrs (!cfg.enableExtensionUpdateCheck) { + mergedUserSettings = + userSettings: enableUpdateCheck: enableExtensionUpdateCheck: + userSettings + // optionalAttrs (enableUpdateCheck == false) { "update.mode" = "none"; } + // optionalAttrs (enableExtensionUpdateCheck == false) { "extensions.autoCheckUpdates" = false; }; -in { - imports = [ - (mkChangedOptionModule [ "programs" "vscode" "immutableExtensionsDir" ] [ - "programs" - "vscode" - "mutableExtensionsDir" - ] (config: !config.programs.vscode.immutableExtensionsDir)) - ]; - - options = { - programs.vscode = { - enable = mkEnableOption "Visual Studio Code"; - - package = mkOption { - type = types.package; - default = pkgs.vscode; - defaultText = literalExpression "pkgs.vscode"; - example = literalExpression "pkgs.vscodium"; - description = '' - Version of Visual Studio Code to install. - ''; - }; - - enableUpdateCheck = mkOption { - type = types.bool; - default = true; - description = '' - Whether to enable update checks/notifications. - ''; - }; - - enableExtensionUpdateCheck = mkOption { - type = types.bool; - default = true; - description = '' - Whether to enable update notifications for extensions. - ''; - }; + profileType = types.submodule { + options = { userSettings = mkOption { type = jsonFormat.type; default = { }; @@ -184,16 +165,6 @@ in { ''; }; - mutableExtensionsDir = mkOption { - type = types.bool; - default = true; - example = false; - description = '' - Whether extensions can be installed or updated manually - or by Visual Studio Code. - ''; - }; - languageSnippets = mkOption { type = jsonFormat.type; default = { }; @@ -221,75 +192,228 @@ in { }; description = "Defines global user snippets."; }; + + enableUpdateCheck = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Whether to enable update checks/notifications. + Can only be set for the default profile, but + it applies to all profiles. + ''; + }; + + enableExtensionUpdateCheck = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Whether to enable update notifications for extensions. + Can only be set for the default profile, but + it applies to all profiles. + ''; + }; + }; + }; + defaultProfile = if cfg.profiles ? default then cfg.profiles.default else { }; + allProfilesExceptDefault = removeAttrs cfg.profiles [ "default" ]; +in { + imports = [ + (mkChangedOptionModule [ "programs" "vscode" "immutableExtensionsDir" ] [ + "programs" + "vscode" + "mutableExtensionsDir" + ] (config: !config.programs.vscode.immutableExtensionsDir)) + ] ++ map (v: + mkRenamedOptionModule [ "programs" "vscode" v ] [ + "programs" + "vscode" + "profiles" + "default" + v + ]) [ + "enableUpdateCheck" + "enableExtensionUpdateCheck" + "userSettings" + "userTasks" + "keybindings" + "extensions" + "languageSnippets" + "globalSnippets" + ]; + + options.programs.vscode = { + enable = mkEnableOption "Visual Studio Code"; + + package = mkOption { + type = types.package; + default = pkgs.vscode; + defaultText = literalExpression "pkgs.vscode"; + example = literalExpression "pkgs.vscodium"; + description = '' + Version of Visual Studio Code to install. + ''; + }; + + mutableExtensionsDir = mkOption { + type = types.bool; + default = allProfilesExceptDefault == { }; + example = false; + description = '' + Whether extensions can be installed or updated manually + or by Visual Studio Code. Mutually exclusive to + programs.vscode.profiles. + ''; + }; + + profiles = mkOption { + type = types.attrsOf profileType; + default = { }; + description = '' + A list of all VSCode profiles. Mutually exclusive + to programs.vscode.mutableExtensionsDir + ''; }; }; config = mkIf cfg.enable { + warnings = [ + (mkIf (allProfilesExceptDefault != { } && cfg.mutableExtensionsDir) + "programs.vscode.mutableExtensionsDir can be used only if no profiles apart from default are set.") + (mkIf ((filterAttrs (n: v: + (v ? enableExtensionUpdateCheck || v ? enableUpdateCheck) + && (v.enableExtensionUpdateCheck != null || v.enableUpdateCheck + != null)) allProfilesExceptDefault) != { }) + "The option programs.vscode.profiles.*.enableExtensionUpdateCheck and option programs.vscode.profiles.*.enableUpdateCheck is invalid for all profiles except default.") + ]; + home.packages = [ cfg.package ]; - home.file = mkMerge [ - (mkIf (mergedUserSettings != { }) { - "${configFilePath}".source = - jsonFormat.generate "vscode-user-settings" mergedUserSettings; - }) - (mkIf (cfg.userTasks != { }) { - "${tasksFilePath}".source = - jsonFormat.generate "vscode-user-tasks" cfg.userTasks; - }) - (mkIf (cfg.keybindings != [ ]) - (let dropNullFields = filterAttrs (_: v: v != null); - in { - "${keybindingsFilePath}".source = - jsonFormat.generate "vscode-keybindings" - (map dropNullFields cfg.keybindings); - })) - (mkIf (cfg.extensions != [ ]) (let - subDir = "share/vscode/extensions"; + # The file `${userDir}/globalStorage/storage.json` needs to be writable by VSCode, + # since it contains other data, such as theme backgrounds, recently opened folders, etc. + # A caveat of adding profiles this way is, VSCode has to be closed + # when this file is being written, since the file is loaded into RAM + # and overwritten on closing VSCode. + home.activation.vscodeProfiles = hm.dag.entryAfter [ "writeBoundary" ] (let + modifyGlobalStorage = + pkgs.writeShellScript "vscode-global-storage-modify" '' + PATH=${makeBinPath [ pkgs.jq ]}''${PATH:+:}$PATH + file="${userDir}/globalStorage/storage.json" + file_write="" + profiles=(${ + escapeShellArgs + (flatten (mapAttrsToList (n: v: n) allProfilesExceptDefault)) + }) + + if [ -f "$file" ]; then + existing_profiles=$(jq '.userDataProfiles // [] | map({ (.name): .location }) | add // {}' "$file") + + for profile in "''${profiles[@]}"; do + if [[ "$(echo $existing_profiles | jq --arg profile $profile 'has ($profile)')" != "true" ]] || [[ "$(echo $existing_profiles | jq --arg profile $profile 'has ($profile)')" == "true" && "$(echo $existing_profiles | jq --arg profile $profile '.[$profile]')" != "\"$profile\"" ]]; then + file_write="$file_write$([ "$file_write" != "" ] && echo "...")$profile" + fi + done + else + for profile in "''${profiles[@]}"; do + file_write="$file_write$([ "$file_write" != "" ] && echo "...")$profile" + done + + mkdir -p $(dirname "$file") + echo "{}" > "$file" + fi + + if [ "$file_write" != "" ]; then + userDataProfiles=$(jq ".userDataProfiles += $(echo $file_write | jq -R 'split("...") | map({ name: ., location: . })')" "$file") + echo $userDataProfiles > "$file" + fi + ''; + in modifyGlobalStorage.outPath); + + home.file = mkMerge (flatten [ + (mapAttrsToList (n: v: [ + (mkIf ((mergedUserSettings v.userSettings v.enableUpdateCheck + v.enableExtensionUpdateCheck) != { }) { + "${configFilePath n}".source = + jsonFormat.generate "vscode-user-settings" + (mergedUserSettings v.userSettings v.enableUpdateCheck + v.enableExtensionUpdateCheck); + }) + + (mkIf (v.userTasks != { }) { + "${tasksFilePath n}".source = + jsonFormat.generate "vscode-user-tasks" v.userTasks; + }) + + (mkIf (v.keybindings != [ ]) { + "${keybindingsFilePath n}".source = + jsonFormat.generate "vscode-keybindings" + (map (filterAttrs (_: v: v != null)) v.keybindings); + }) + + (mkIf (v.languageSnippets != { }) (mapAttrs' (language: snippet: + nameValuePair "${snippetDir n}/${language}.json" { + source = + jsonFormat.generate "user-snippet-${language}.json" snippet; + }) v.languageSnippets)) + + (mkIf (v.globalSnippets != { }) { + "${snippetDir n}/global.code-snippets".source = + jsonFormat.generate "user-snippet-global.code-snippets" + v.globalSnippets; + }) + ]) cfg.profiles) + + # We write extensions.json for all profiles, except the default profile, + # since that is handled by code below. + (mkIf (allProfilesExceptDefault != { }) (mapAttrs' (n: v: + nameValuePair "${userDir}/profiles/${n}/extensions.json" { + source = "${ + extensionJsonFile n (extensionJson v.extensions) + }/share/vscode/extensions/extensions.json"; + }) allProfilesExceptDefault)) + + (mkIf (cfg.profiles != { }) (let # Adapted from https://discourse.nixos.org/t/vscode-extensions-setup/1801/2 + subDir = "share/vscode/extensions"; toPaths = ext: map (k: { "${extensionPath}/${k}".source = "${ext}/${subDir}/${k}"; }) (if ext ? vscodeExtUniqueId then [ ext.vscodeExtUniqueId ] else builtins.attrNames (builtins.readDir (ext + "/${subDir}"))); - in if cfg.mutableExtensionsDir then - mkMerge (concatMap toPaths cfg.extensions - ++ lib.optional (lib.versionAtLeast vscodeVersion "1.74.0") { - # Whenever our immutable extensions.json changes, force VSCode to regenerate - # extensions.json with both mutable and immutable extensions. - "${extensionPath}/.extensions-immutable.json" = { - text = extensionJson; - onChange = '' - run rm $VERBOSE_ARG -f ${extensionPath}/{extensions.json,.init-default-profile-extensions} - verboseEcho "Regenerating VSCode extensions.json" - run ${getExe cfg.package} --list-extensions > /dev/null - ''; - }; - }) + in if (cfg.mutableExtensionsDir && allProfilesExceptDefault == { }) then + # Mutable extensions dir can only occur when only default profile is set. + # Force regenerating extensions.json using the below method, + # causes VSCode to create the extensions.json with all the extensions + # in the extension directory, which includes extensions from other profiles. + mkMerge (concatMap toPaths + (flatten (mapAttrsToList (n: v: v.extensions) cfg.profiles)) + ++ optional + ((versionAtLeast vscodeVersion "1.74.0" || vscodePname == "cursor") + && defaultProfile != { }) { + # Whenever our immutable extensions.json changes, force VSCode to regenerate + # extensions.json with both mutable and immutable extensions. + "${extensionPath}/.extensions-immutable.json" = { + text = extensionJson defaultProfile.extensions; + onChange = '' + run rm $VERBOSE_ARG -f ${extensionPath}/{extensions.json,.init-default-profile-extensions} + verboseEcho "Regenerating VSCode extensions.json" + run ${getExe cfg.package} --list-extensions > /dev/null + ''; + }; + }) else { "${extensionPath}".source = let combinedExtensionsDrv = pkgs.buildEnv { name = "vscode-extensions"; - paths = cfg.extensions - ++ lib.optional (lib.versionAtLeast vscodeVersion "1.74.0") - extensionJsonFile; + paths = (flatten (mapAttrsToList (n: v: v.extensions) cfg.profiles)) + ++ optional ((versionAtLeast vscodeVersion "1.74.0" || vscodePname + == "cursor") && defaultProfile != { }) + (extensionJsonFile "default" + (extensionJson defaultProfile.extensions)); }; in "${combinedExtensionsDrv}/${subDir}"; })) - - (mkIf (cfg.globalSnippets != { }) - (let globalSnippets = "${snippetDir}/global.code-snippets"; - in { - "${globalSnippets}".source = - jsonFormat.generate "user-snippet-global.code-snippets" - cfg.globalSnippets; - })) - - (lib.mapAttrs' (language: snippet: - lib.nameValuePair "${snippetDir}/${language}.json" { - source = jsonFormat.generate "user-snippet-${language}.json" snippet; - }) cfg.languageSnippets) - ]; + ]); }; } diff --git a/modules/programs/vscode/haskell.nix b/modules/programs/vscode/haskell.nix index 63ecd18e2..450c748e4 100644 --- a/modules/programs/vscode/haskell.nix +++ b/modules/programs/vscode/haskell.nix @@ -52,12 +52,12 @@ in { }; config = mkIf cfg.enable { - programs.vscode.userSettings = mkIf cfg.hie.enable { + programs.vscode.profiles.default.userSettings = mkIf cfg.hie.enable { "languageServerHaskell.enableHIE" = true; "languageServerHaskell.hieExecutablePath" = cfg.hie.executablePath; }; - programs.vscode.extensions = + programs.vscode.profiles.default.extensions = [ pkgs.vscode-extensions.justusadam.language-haskell ] ++ lib.optional cfg.hie.enable pkgs.vscode-extensions.alanz.vscode-hie-server; diff --git a/modules/programs/watson.nix b/modules/programs/watson.nix index 1f9864559..f830d28d0 100644 --- a/modules/programs/watson.nix +++ b/modules/programs/watson.nix @@ -80,7 +80,7 @@ in { source ${cfg.package}/share/bash-completion/completions/watson ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' source ${cfg.package}/share/zsh/site-functions/_watson ''; diff --git a/modules/programs/waybar.nix b/modules/programs/waybar.nix index 48a7fa5f7..c0ce4c169 100644 --- a/modules/programs/waybar.nix +++ b/modules/programs/waybar.nix @@ -211,6 +211,17 @@ in { ''; }; + systemd.enableInspect = mkOption { + type = bool; + default = false; + example = true; + description = '' + Inspect objects and find their CSS classes, experiment with live CSS styles, and lookup the current value of CSS properties. + + See + ''; + }; + style = mkOption { type = nullOr (either path lines); default = null; @@ -310,7 +321,7 @@ in { Description = "Highly customizable Wayland bar for Sway and Wlroots based compositors."; Documentation = "https://github.com/Alexays/Waybar/wiki"; - PartOf = [ cfg.systemd.target ]; + PartOf = [ cfg.systemd.target "tray.target" ]; After = [ cfg.systemd.target ]; ConditionEnvironment = "WAYLAND_DISPLAY"; X-Restart-Triggers = optional (settings != [ ]) @@ -324,10 +335,12 @@ in { ExecReload = "${pkgs.coreutils}/bin/kill -SIGUSR2 $MAINPID"; Restart = "on-failure"; KillMode = "mixed"; + } // optionalAttrs cfg.systemd.enableInspect { + Environment = [ "GTK_DEBUG=interactive" ]; }; - Install.WantedBy = - lib.optional (cfg.systemd.target != null) cfg.systemd.target; + Install.WantedBy = [ "tray.target" ] + ++ lib.optional (cfg.systemd.target != null) cfg.systemd.target; }; }) ]); diff --git a/modules/programs/waylogout.nix b/modules/programs/waylogout.nix new file mode 100644 index 000000000..cb6dc4bb9 --- /dev/null +++ b/modules/programs/waylogout.nix @@ -0,0 +1,53 @@ +{ pkgs, config, lib, ... }: +let cfg = config.programs.waylogout; +in { + meta.maintainers = [ lib.hm.maintainers.noodlez ]; + + options.programs.waylogout = { + enable = lib.mkOption { + default = false; + type = lib.types.bool; + example = true; + description = '' + Whether or not to enable waylogout. + ''; + }; + + package = lib.mkPackageOption pkgs "waylogout" { nullable = true; }; + + settings = lib.mkOption { + type = with lib.types; attrsOf (oneOf [ bool float int path str ]); + default = { }; + description = '' + Default arguments to {command}`waylogout`. An empty set + disables configuration generation. + ''; + example = { + color = "808080"; + poweroff-command = "systemctl poweroff"; + reboot-command = "systemctl reboot"; + scaling = "fit"; + effect-blur = "7x4"; + screenshots = true; + }; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "programs.waylogout" pkgs + lib.platforms.linux) + ]; + + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + + xdg.configFile."waylogout/config" = lib.mkIf (cfg.settings != { }) { + text = lib.concatStrings (lib.mapAttrsToList (n: v: + if v == false then + "" + else + (if v == true then n else n + "=" + builtins.toString v) + "\n") + cfg.settings); + }; + }; +} diff --git a/modules/programs/wezterm.nix b/modules/programs/wezterm.nix index c1478d64a..41e0a5bee 100644 --- a/modules/programs/wezterm.nix +++ b/modules/programs/wezterm.nix @@ -108,6 +108,7 @@ in { programs.bash.initExtra = mkIf cfg.enableBashIntegration shellIntegrationStr; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration shellIntegrationStr; + programs.zsh.initContent = + mkIf cfg.enableZshIntegration shellIntegrationStr; }; } diff --git a/modules/programs/wlogout.nix b/modules/programs/wlogout.nix index b01f8a0ae..6b318e109 100644 --- a/modules/programs/wlogout.nix +++ b/modules/programs/wlogout.nix @@ -72,7 +72,7 @@ in { options.programs.wlogout = with lib.types; { enable = mkEnableOption "wlogout"; - package = mkPackageOption pkgs "wlogout" { }; + package = mkPackageOption pkgs "wlogout" { nullable = true; }; layout = mkOption { type = listOf wlogoutLayoutConfig; @@ -132,7 +132,7 @@ in { lib.platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."wlogout/layout" = mkIf (cfg.layout != [ ]) { source = pkgs.writeText "wlogout/layout" layoutContent; diff --git a/modules/programs/wofi.nix b/modules/programs/wofi.nix index 1317716ed..5ff7a58cd 100644 --- a/modules/programs/wofi.nix +++ b/modules/programs/wofi.nix @@ -17,7 +17,7 @@ in { enable = mkEnableOption "wofi: a launcher/menu program for wlroots based wayland compositors such as sway"; - package = mkPackageOption pkgs "wofi" { }; + package = mkPackageOption pkgs "wofi" { nullable = true; }; settings = mkOption { default = { }; @@ -37,7 +37,7 @@ in { style = mkOption { default = null; - type = types.nullOr types.str; + type = types.nullOr types.lines; description = '' CSS style for wofi to use as a stylesheet. See {manpage}`wofi(7)`. @@ -58,7 +58,7 @@ in { assertions = [ (hm.assertions.assertPlatform "programs.wofi" pkgs platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile = mkMerge [ (mkIf (cfg.settings != { }) { diff --git a/modules/programs/wpaperd.nix b/modules/programs/wpaperd.nix deleted file mode 100644 index 655024a06..000000000 --- a/modules/programs/wpaperd.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.programs.wpaperd; - tomlFormat = pkgs.formats.toml { }; -in { - meta.maintainers = [ hm.maintainers.Avimitin ]; - - options.programs.wpaperd = { - enable = mkEnableOption "wpaperd"; - - package = mkPackageOption pkgs "wpaperd" { }; - - settings = mkOption { - type = tomlFormat.type; - default = { }; - example = literalExpression '' - { - eDP-1 = { - path = "/home/foo/Pictures/Wallpaper"; - apply-shadow = true; - }; - DP-2 = { - path = "/home/foo/Pictures/Anime"; - sorting = "descending"; - }; - } - ''; - description = '' - Configuration written to - {file}`$XDG_CONFIG_HOME/wpaperd/wallpaper.toml`. - See - for the full list of options. - ''; - }; - }; - - config = mkIf cfg.enable { - home.packages = [ cfg.package ]; - - xdg.configFile = { - "wpaperd/wallpaper.toml" = mkIf (cfg.settings != { }) { - source = tomlFormat.generate "wpaperd-wallpaper" cfg.settings; - }; - }; - }; -} diff --git a/modules/programs/xplr.nix b/modules/programs/xplr.nix index bd9222954..ddbbc1133 100644 --- a/modules/programs/xplr.nix +++ b/modules/programs/xplr.nix @@ -9,7 +9,7 @@ let version = '${cfg.package.version}' ''; - # If `value` is a Nix store path, create the symlink `/nix/store/newhash/${name}/*` + # If `value` is a Nix store path, create the symlink `/nix/store/newhash/${name}/*` # to `/nix/store/oldhash/*` and returns `/nix/store/newhash`. wrapPlugin = name: value: if lib.isStorePath value then @@ -49,7 +49,7 @@ in { options.programs.xplr = { enable = mkEnableOption "xplr, terminal UI based file explorer"; - package = mkPackageOption pkgs "xplr" { }; + package = mkPackageOption pkgs "xplr" { nullable = true; }; plugins = mkOption { type = with types; nullOr (attrsOf (either package str)); @@ -58,7 +58,7 @@ in { description = '' An attribute set of plugin paths to be added to the [package.path] of the {file}`~/config/xplr/init.lua` configuration file. - Must be a package or string representing the plugin directory's path. + Must be a package or string representing the plugin directory's path. If the path string is not absolute, it will be relative to {file}`$XDG_CONFIG_HOME/xplr/init.lua`. ''; example = literalExpression '' @@ -91,7 +91,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."xplr/init.lua".source = pkgs.writeText "init.lua" configFile; diff --git a/modules/programs/yambar.nix b/modules/programs/yambar.nix index f4e0a434a..efda8f19e 100644 --- a/modules/programs/yambar.nix +++ b/modules/programs/yambar.nix @@ -11,7 +11,7 @@ in { options.programs.yambar = { enable = lib.mkEnableOption "Yambar"; - package = lib.mkPackageOption pkgs "yambar" { }; + package = lib.mkPackageOption pkgs "yambar" { nullable = true; }; settings = lib.mkOption { type = yamlFormat.type; @@ -46,7 +46,7 @@ in { lib.platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."yambar/config.yml" = lib.mkIf (cfg.settings != { }) { source = yamlFormat.generate "config.yml" cfg.settings; diff --git a/modules/programs/yazi.nix b/modules/programs/yazi.nix index 1985d2d3a..4ed6fc981 100644 --- a/modules/programs/yazi.nix +++ b/modules/programs/yazi.nix @@ -14,7 +14,7 @@ in { options.programs.yazi = { enable = mkEnableOption "yazi"; - package = lib.mkPackageOption pkgs "yazi" { }; + package = lib.mkPackageOption pkgs "yazi" { nullable = true; }; shellWrapperName = lib.mkOption { type = types.str; @@ -163,7 +163,7 @@ in { }; config = mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; programs = let bashIntegration = '' @@ -214,7 +214,7 @@ in { in { bash.initExtra = mkIf cfg.enableBashIntegration bashIntegration; - zsh.initExtra = mkIf cfg.enableZshIntegration bashIntegration; + zsh.initContent = mkIf cfg.enableZshIntegration bashIntegration; fish.functions.${cfg.shellWrapperName} = mkIf cfg.enableFishIntegration fishIntegration; diff --git a/modules/programs/z-lua.nix b/modules/programs/z-lua.nix index 4164aa394..afbf4d282 100644 --- a/modules/programs/z-lua.nix +++ b/modules/programs/z-lua.nix @@ -56,7 +56,7 @@ in { })" ''; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' + programs.zsh.initContent = mkIf cfg.enableZshIntegration '' eval "$(${pkgs.z-lua}/bin/z --init zsh ${ concatStringsSep " " cfg.options })" diff --git a/modules/programs/zellij.nix b/modules/programs/zellij.nix index 8d5f00051..447be014e 100644 --- a/modules/programs/zellij.nix +++ b/modules/programs/zellij.nix @@ -1,32 +1,28 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) mkIf mkOption types; cfg = config.programs.zellij; yamlFormat = pkgs.formats.yaml { }; - zellijCmd = getExe cfg.package; + mkShellIntegrationOption = option: + option // { + default = false; + example = true; + }; in { - meta.maintainers = [ hm.maintainers.mainrs ]; + meta.maintainers = [ lib.maintainers.khaneliman lib.hm.maintainers.mainrs ]; options.programs.zellij = { - enable = mkEnableOption "zellij"; + enable = lib.mkEnableOption "Zellij"; - package = mkOption { - type = types.package; - default = pkgs.zellij; - defaultText = literalExpression "pkgs.zellij"; - description = '' - The zellij package to install. - ''; - }; + package = lib.mkPackageOption pkgs "zellij" { }; - settings = mkOption { + settings = lib.mkOption { type = yamlFormat.type; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { theme = "custom"; themes.custom.fg = "#ffffff"; @@ -44,42 +40,81 @@ in { ''; }; - enableBashIntegration = - lib.hm.shell.mkBashIntegrationOption { inherit config; }; + attachExistingSession = mkOption { + type = types.bool; + default = false; + description = '' + Whether to attach to the default session after being autostarted if a Zellij session already exists. - enableFishIntegration = - lib.hm.shell.mkFishIntegrationOption { inherit config; }; + Variable is checked in `auto-start` script. Requires shell integration to be enabled to have effect. + ''; + }; - enableZshIntegration = - lib.hm.shell.mkZshIntegrationOption { inherit config; }; + exitShellOnExit = mkOption { + type = types.bool; + default = false; + description = '' + Whether to exit the shell when Zellij exits after being autostarted. + + Variable is checked in `auto-start` script. Requires shell integration to be enabled to have effect. + ''; + }; + + enableBashIntegration = mkShellIntegrationOption + (lib.hm.shell.mkBashIntegrationOption { inherit config; }); + + enableFishIntegration = mkShellIntegrationOption + (lib.hm.shell.mkFishIntegrationOption { inherit config; }); + + enableZshIntegration = mkShellIntegrationOption + (lib.hm.shell.mkZshIntegrationOption { inherit config; }); }; - config = mkIf cfg.enable { + config = let + shellIntegrationEnabled = (cfg.enableBashIntegration + || cfg.enableZshIntegration || cfg.enableFishIntegration); + in mkIf cfg.enable { home.packages = [ cfg.package ]; # Zellij switched from yaml to KDL in version 0.32.0: # https://github.com/zellij-org/zellij/releases/tag/v0.32.0 xdg.configFile."zellij/config.yaml" = mkIf - (cfg.settings != { } && (versionOlder cfg.package.version "0.32.0")) { + (cfg.settings != { } && (lib.versionOlder cfg.package.version "0.32.0")) { source = yamlFormat.generate "zellij.yaml" cfg.settings; }; - xdg.configFile."zellij/config.kdl" = mkIf - (cfg.settings != { } && (versionAtLeast cfg.package.version "0.32.0")) { + xdg.configFile."zellij/config.kdl" = mkIf (cfg.settings != { } + && (lib.versionAtLeast cfg.package.version "0.32.0")) { text = lib.hm.generators.toKDL { } cfg.settings; }; - programs.bash.initExtra = mkIf cfg.enableBashIntegration (mkOrder 200 '' - eval "$(${zellijCmd} setup --generate-auto-start bash)" + programs.bash.initExtra = mkIf cfg.enableBashIntegration '' + eval "$(${lib.getExe cfg.package} setup --generate-auto-start bash)" + ''; + + programs.zsh.initContent = mkIf cfg.enableZshIntegration (lib.mkOrder 200 '' + eval "$(${lib.getExe cfg.package} setup --generate-auto-start zsh)" ''); - programs.zsh.initExtra = mkIf cfg.enableZshIntegration (mkOrder 200 '' - eval "$(${zellijCmd} setup --generate-auto-start zsh)" - ''); + programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration '' + eval (${ + lib.getExe cfg.package + } setup --generate-auto-start fish | string collect) + ''; - programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration - (mkOrder 200 '' - eval (${zellijCmd} setup --generate-auto-start fish | string collect) - ''); + home.sessionVariables = mkIf shellIntegrationEnabled { + ZELLIJ_AUTO_ATTACH = + if cfg.attachExistingSession then "true" else "false"; + ZELLIJ_AUTO_EXIT = if cfg.exitShellOnExit then "true" else "false"; + }; + + warnings = + lib.optional (cfg.attachExistingSession && !shellIntegrationEnabled) '' + You have enabled `programs.zellij.attachExistingSession`, but none of the shell integrations are enabled. + This option will have no effect. + '' ++ lib.optional (cfg.exitShellOnExit && !shellIntegrationEnabled) '' + You have enabled `programs.zellij.exitShellOnExit`, but none of the shell integrations are enabled. + This option will have no effect. + ''; }; } diff --git a/modules/programs/zk.nix b/modules/programs/zk.nix index d4abfe279..cffce3738 100644 --- a/modules/programs/zk.nix +++ b/modules/programs/zk.nix @@ -11,7 +11,7 @@ in { options.programs.zk = { enable = lib.mkEnableOption "zk"; - package = lib.mkPackageOption pkgs "zk" { }; + package = lib.mkPackageOption pkgs "zk" { nullable = true; }; settings = lib.mkOption { type = tomlFormat.type; @@ -43,7 +43,7 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."zk/config.toml" = lib.mkIf (cfg.settings != { }) { source = tomlFormat.generate "config.toml" cfg.settings; diff --git a/modules/programs/zoxide.nix b/modules/programs/zoxide.nix index e736d45ab..27544cb5d 100644 --- a/modules/programs/zoxide.nix +++ b/modules/programs/zoxide.nix @@ -1,30 +1,25 @@ { config, lib, pkgs, ... }: - -with lib; - let - cfg = config.programs.zoxide; - cfgOptions = concatStringsSep " " cfg.options; - + cfgOptions = lib.concatStringsSep " " cfg.options; in { meta.maintainers = [ ]; options.programs.zoxide = { - enable = mkEnableOption "zoxide"; + enable = lib.mkEnableOption "zoxide"; package = lib.mkOption { - type = types.package; + type = lib.types.package; default = pkgs.zoxide; - defaultText = literalExpression "pkgs.zoxide"; + defaultText = lib.literalExpression "pkgs.zoxide"; description = '' Zoxide package to install. ''; }; options = lib.mkOption { - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "--no-cmd" ]; description = '' @@ -53,22 +48,24 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { home.packages = [ cfg.package ]; - programs.bash.initExtra = mkIf cfg.enableBashIntegration (mkOrder 150 '' - eval "$(${cfg.package}/bin/zoxide init bash ${cfgOptions})" - ''); + programs.bash.initExtra = lib.mkIf cfg.enableBashIntegration + (lib.mkOrder 2000 '' + eval "$(${cfg.package}/bin/zoxide init bash ${cfgOptions})" + ''); - programs.zsh.initExtra = mkIf cfg.enableZshIntegration '' - eval "$(${cfg.package}/bin/zoxide init zsh ${cfgOptions})" - ''; + programs.zsh.initContent = lib.mkIf cfg.enableZshIntegration + (lib.mkOrder 2000 '' + eval "$(${cfg.package}/bin/zoxide init zsh ${cfgOptions})" + ''); - programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration '' + programs.fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration '' ${cfg.package}/bin/zoxide init fish ${cfgOptions} | source ''; - programs.nushell = mkIf cfg.enableNushellIntegration { + programs.nushell = lib.mkIf cfg.enableNushellIntegration { extraEnv = '' let zoxide_cache = "${config.xdg.cacheHome}/zoxide" if not ($zoxide_cache | path exists) { diff --git a/modules/programs/zplug.nix b/modules/programs/zplug.nix index 94e3173a4..8c47915f8 100644 --- a/modules/programs/zplug.nix +++ b/modules/programs/zplug.nix @@ -44,7 +44,7 @@ in { config = mkIf cfg.enable { home.packages = [ pkgs.zplug ]; - programs.zsh.initExtraBeforeCompInit = '' + programs.zsh.initContent = mkOrder 550 '' export ZPLUG_HOME=${cfg.zplugHome} source ${pkgs.zplug}/share/zplug/init.zsh diff --git a/modules/programs/zsh.nix b/modules/programs/zsh.nix index 25adab2d2..4dffce2b0 100644 --- a/modules/programs/zsh.nix +++ b/modules/programs/zsh.nix @@ -1,309 +1,290 @@ { config, lib, pkgs, ... }: - -with lib; - let + inherit (lib) concatStringsSep literalExpression mkEnableOption mkIf mkOption mkOrder optionalString types; 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; + stateVersion = config.home.stateVersion; 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). - ''; - }; - - saveNoDups = mkOption { - type = types.bool; - default = false; - description = '' - Do not write duplicate entries into the history file. - ''; - }; - - findNoDups = mkOption { - type = types.bool; - default = false; - description = '' - Do not display a line previously found in the history - file. - ''; - }; - - 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" ]) + (lib.mkRenamedOptionModule [ "programs" "zsh" "enableAutosuggestions" ] [ "programs" "zsh" "autosuggestion" "enable" ]) + (lib.mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ]) + (lib.mkRenamedOptionModule [ "programs" "zsh" "zproof" ] [ "programs" "zsh" "zprof" ]) ]; - options = { + options = + let + 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 lib.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). + ''; + }; + + saveNoDups = mkOption { + type = types.bool; + default = false; + description = '' + Do not write duplicate entries into the history file. + ''; + }; + + findNoDups = mkOption { + type = types.bool; + default = false; + description = '' + Do not display a line previously found in the history + file. + ''; + }; + + 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 = lib.mkDefault "${config.name}.plugin.zsh"; + }); + + ohMyZshModule = types.submodule { + options = { + enable = mkEnableOption "oh-my-zsh"; + + package = lib.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 = lib.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 { programs.zsh = { enable = mkEnableOption "Z shell (Zsh)"; - package = mkPackageOption pkgs "zsh" { }; + package = lib.mkPackageOption pkgs "zsh" { }; autocd = mkOption { default = null; @@ -458,7 +439,7 @@ in }; defaultKeymap = mkOption { - type = types.nullOr (types.enum (attrNames bindkeyCommands)); + type = types.nullOr (types.enum (lib.attrNames bindkeyCommands)); default = null; example = "emacs"; description = "The default base keymap to use."; @@ -471,6 +452,17 @@ in description = "Environment variables that will be set for zsh session."; }; + initContent = mkOption { + default = ""; + type = types.lines; + example = lib.literalExpression '' + lib.mkOrder 1000 '''' + echo "Hello zsh initContent!" + ''''; + ''; + description = "Content to be added to {file}`.zshrc`. To specify the order, use `lib.mkOrder`."; + }; + initExtraBeforeCompInit = mkOption { default = ""; type = types.lines; @@ -560,7 +552,25 @@ in }; }; - config = mkIf cfg.enable (mkMerge [ + config = + let + 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" ( + lib.mapAttrsToList (k: v: "alias -- ${lib.escapeShellArg k}=${lib.escapeShellArg v}") cfg.shellAliases + ); + + dirHashesStr = concatStringsSep "\n" ( + lib.mapAttrsToList (k: v: ''hash -d ${k}="${v}"'') cfg.dirHashes + ); + + zdotdir = "$HOME/" + lib.escapeShellArg cfg.dotDir; + in + mkIf cfg.enable (lib.mkMerge [ (mkIf (cfg.envExtra != "") { home.file."${relToDotDir ".zshenv"}".text = cfg.envExtra; }) @@ -613,161 +623,161 @@ in { home.packages = [ cfg.package ] - ++ optional cfg.enableCompletion pkgs.nix-zsh-completions - ++ optional cfg.oh-my-zsh.enable cfg.oh-my-zsh.package; + ++ lib.optional cfg.enableCompletion pkgs.nix-zsh-completions + ++ lib.optional cfg.oh-my-zsh.enable cfg.oh-my-zsh.package; - home.file."${relToDotDir ".zshrc"}".text = concatStringsSep "\n" ([ + programs.zsh.initContent = lib.mkMerge [ # zprof must be loaded before everything else, since it # benchmarks the shell initialization. - (optionalString cfg.zprof.enable '' + (lib.mkIf cfg.zprof.enable (mkOrder 400 '' zmodload zsh/zprof - '') + '')) - cfg.initExtraFirst - "typeset -U path cdpath fpath manpath" + (lib.mkIf (cfg.initExtraFirst != "") (lib.mkBefore cfg.initExtraFirst)) - (optionalString (cfg.cdpath != []) '' + (mkOrder 510 "typeset -U path cdpath fpath manpath") + + (lib.mkIf (cfg.cdpath != [ ]) (mkOrder 510 '' cdpath+=(${concatStringsSep " " cfg.cdpath}) + '')) + + (mkOrder 520 '' + 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" '') - '' - 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) '' + (lib.mkIf (cfg.defaultKeymap != null) (mkOrder 530 '' # Use ${cfg.defaultKeymap} keymap as the default. - ${getAttr cfg.defaultKeymap bindkeyCommands} - '') - localVarsStr + ${lib.getAttr cfg.defaultKeymap bindkeyCommands} + '')) - cfg.initExtraBeforeCompInit + (lib.mkIf (localVarsStr != "") (mkOrder 540 localVarsStr)) - (concatStrings (map (plugin: '' + (lib.mkIf (cfg.initExtraBeforeCompInit != "") (mkOrder 550 cfg.initExtraBeforeCompInit)) + + (lib.mkIf (cfg.plugins != []) (mkOrder 560 (lib.concatStrings (map (plugin: '' path+="$HOME/${pluginsDir}/${plugin.name}" fpath+="$HOME/${pluginsDir}/${plugin.name}" - '') cfg.plugins)) + '') cfg.plugins)))) - '' - # Oh-My-Zsh/Prezto calls compinit during initialization, + # NOTE: 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 - }'' + (lib.mkIf (cfg.enableCompletion && !cfg.oh-my-zsh.enable && !cfg.prezto.enable) + (mkOrder 570 cfg.completionInit)) - (optionalString cfg.autosuggestion.enable '' + (lib.mkIf cfg.autosuggestion.enable (mkOrder 700 '' 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.autosuggestion.strategy != [ ]) '' + ZSH_AUTOSUGGEST_STRATEGY=(${ + concatStringsSep " " cfg.autosuggestion.strategy + }) + ''}${optionalString (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 - '') + (lib.mkIf cfg.oh-my-zsh.enable (mkOrder 800 '' + # 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 "${cfg.prezto.package}/share/zsh-prezto/runcoms/zshrc")} + (mkOrder 900 ((optionalString cfg.prezto.enable (builtins.readFile + "${cfg.prezto.package}/share/zsh-prezto/runcoms/zshrc")) + + (lib.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 lib.versionAtLeast stateVersion "20.03" then + ''HISTFILE="${cfg.history.path}"'' + else + ''HISTFILE="$HOME/${cfg.history.path}"''} + mkdir -p "$(dirname "$HISTFILE")" - ${concatStrings (map (plugin: '' - if [[ -f "$HOME/${pluginsDir}/${plugin.name}/${plugin.file}" ]]; then - source "$HOME/${pluginsDir}/${plugin.name}/${plugin.file}" - fi - '') cfg.plugins)} + 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.saveNoDups then "setopt" else "unsetopt"} HIST_SAVE_NO_DUPS + ${if cfg.history.findNoDups then "setopt" else "unsetopt"} HIST_FIND_NO_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 ""} + '')) - # 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")" + (lib.mkIf (cfg.initExtra != "") cfg.initExtra) - 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.saveNoDups then "setopt" else "unsetopt"} HIST_SAVE_NO_DUPS - ${if cfg.history.findNoDups then "setopt" else "unsetopt"} HIST_FIND_NO_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 ""} + (lib.mkIf (aliasesStr != "" || cfg.shellGlobalAliases != {}) (mkOrder 1100 + ((optionalString (aliasesStr != "") aliasesStr) + + (optionalString (cfg.shellGlobalAliases != {}) + (optionalString (cfg.shellAliases != {}) "\n" + + (concatStringsSep "\n" (lib.mapAttrsToList + (k: v: "alias -g -- ${lib.escapeShellArg k}=${lib.escapeShellArg v}") + cfg.shellGlobalAliases))))))) - ${cfg.initExtra} + (lib.mkIf (dirHashesStr != "") (mkOrder 1150 '' + # Named Directory Hashes + ${dirHashesStr} + '')) - # Aliases - ${aliasesStr} - '' - ] - ++ (mapAttrsToList (k: v: "alias -g -- ${lib.escapeShellArg k}=${lib.escapeShellArg v}") cfg.shellGlobalAliases) - ++ [ ('' - # Named Directory Hashes - ${dirHashesStr} - '') - - (optionalString cfg.syntaxHighlighting.enable + (lib.mkIf cfg.syntaxHighlighting.enable (mkOrder 1200 # 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" ( + '' + 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})") + (name: value: "ZSH_HIGHLIGHT_STYLES[${lib.escapeShellArg name}]=${lib.escapeShellArg value}") cfg.syntaxHighlighting.styles - )} - ${lib.concatStringsSep "\n" ( + )} + ${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) + (lib.mkIf (cfg.historySubstringSearch.enable or false) (mkOrder 1250 # 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) - } - '') + '' + 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 - '') - ]); + (lib.mkIf cfg.zprof.enable (mkOrder 1450 "zprof")) + ]; + + home.file."${relToDotDir ".zshrc"}".text = cfg.initContent; } (mkIf cfg.oh-my-zsh.enable { @@ -779,10 +789,10 @@ in (mkIf (cfg.plugins != []) { # Many plugins require compinit to be called # but allow the user to opt out. - programs.zsh.enableCompletion = mkDefault true; + programs.zsh.enableCompletion = lib.mkDefault true; home.file = - foldl' (a: b: a // b) {} + lib.foldl' (a: b: a // b) {} (map (plugin: { "${pluginsDir}/${plugin.name}".source = plugin.src; }) cfg.plugins); }) diff --git a/modules/services/amberol.nix b/modules/services/amberol.nix index a63012447..7aa169db4 100644 --- a/modules/services/amberol.nix +++ b/modules/services/amberol.nix @@ -54,7 +54,7 @@ in { Unit = { Description = "Amberol music player daemon"; Requires = [ "dbus.service" ]; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/autorandr.nix b/modules/services/autorandr.nix index 64e6008e8..89ee612b2 100644 --- a/modules/services/autorandr.nix +++ b/modules/services/autorandr.nix @@ -36,7 +36,7 @@ in { systemd.user.services.autorandr = { Unit = { Description = "autorandr"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/barrier.nix b/modules/services/barrier.nix index 513a7e749..59c4cbf75 100644 --- a/modules/services/barrier.nix +++ b/modules/services/barrier.nix @@ -63,7 +63,7 @@ in { systemd.user.services.barrierc = { Unit = { Description = "Barrier Client daemon"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; Install.WantedBy = [ "graphical-session.target" ]; diff --git a/modules/services/batsignal.nix b/modules/services/batsignal.nix index 4f209f1e0..be5cf5347 100644 --- a/modules/services/batsignal.nix +++ b/modules/services/batsignal.nix @@ -32,7 +32,7 @@ in { systemd.user.services.batsignal = { Unit = { Description = "batsignal - battery monitor daemon"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/blanket.nix b/modules/services/blanket.nix index 5eeb2ab1e..bcc08ac85 100644 --- a/modules/services/blanket.nix +++ b/modules/services/blanket.nix @@ -24,7 +24,7 @@ in { Unit = { Description = "Blanket daemon"; Requires = [ "dbus.service" ]; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" "pipewire.service" ]; }; diff --git a/modules/services/blueman-applet.nix b/modules/services/blueman-applet.nix index 5211534c4..47f81b48c 100644 --- a/modules/services/blueman-applet.nix +++ b/modules/services/blueman-applet.nix @@ -30,7 +30,7 @@ with lib; Unit = { Description = "Blueman applet"; Requires = [ "tray.target" ]; - After = [ "graphical-session-pre.target" "tray.target" ]; + After = [ "graphical-session.target" "tray.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/cbatticon.nix b/modules/services/cbatticon.nix index 1616b2dcd..eebb5bdbc 100644 --- a/modules/services/cbatticon.nix +++ b/modules/services/cbatticon.nix @@ -118,7 +118,7 @@ in { Unit = { Description = "cbatticon system tray battery icon"; Requires = [ "tray.target" ]; - After = [ "graphical-session-pre.target" "tray.target" ]; + After = [ "graphical-session.target" "tray.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/clipse.nix b/modules/services/clipse.nix new file mode 100644 index 000000000..1d0ee95fd --- /dev/null +++ b/modules/services/clipse.nix @@ -0,0 +1,167 @@ +{ pkgs, config, lib, ... }: +let + cfg = config.services.clipse; + jsonFormat = pkgs.formats.json { }; +in { + meta.maintainers = [ lib.hm.maintainers.dsoverlord ]; + + options.services.clipse = { + enable = lib.mkEnableOption "Enable clipse clipboard manager"; + + package = lib.mkPackageOption pkgs "clipse" { nullable = true; }; + + systemdTarget = lib.mkOption { + type = lib.types.str; + default = "graphical-session.target"; + example = "sway-session.target"; + description = '' + The systemd target that will automatically start the clipse service. + + When setting this value to `"sway-session.target"`, + make sure to also enable {option}`wayland.windowManager.sway.systemd.enable`, + otherwise the service may never be started. + ''; + }; + + allowDuplicates = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Allow duplicates"; + }; + + historySize = lib.mkOption { + type = lib.types.int; + default = 100; + description = "Number of history lines to keep."; + }; + + imageDisplay = { + type = lib.mkOption { + type = lib.types.enum [ "basic" "kitty" "sixel" ]; + default = "basic"; + description = "Preview image method"; + }; + + scaleX = lib.mkOption { + type = lib.types.int; + default = 9; + description = "Image scaling factor X"; + }; + + scaleY = lib.mkOption { + type = lib.types.int; + default = 9; + description = "Image scaling factor Y"; + }; + + heightCut = lib.mkOption { + type = lib.types.int; + default = 2; + description = "Height cut"; + }; + }; + + keyBindings = lib.mkOption { + type = jsonFormat.type; + + default = { }; + + example = lib.literalExpression '' + { + "choose": "enter", + "clearSelected": "S", + "down": "down", + "end": "end", + "filter": "/", + "home": "home", + "more": "?", + "nextPage": "right", + "prevPage": "left", + "preview": "t", + "quit": "q", + "remove": "x", + "selectDown": "ctrl+down", + "selectSingle": "s", + "selectUp": "ctrl+up", + "togglePin": "p", + "togglePinned": "tab", + "up": "up", + "yankFilter": "ctrl+s" + } + ''; + + description = "Custom key bindings"; + }; + + theme = lib.mkOption { + type = jsonFormat.type; + + default = { useCustomTheme = false; }; + + example = lib.literalExpression '' + { + useCustomTheme = true; + DimmedDesc = "#ffffff"; + DimmedTitle = "#ffffff"; + FilteredMatch = "#ffffff"; + NormalDesc = "#ffffff"; + NormalTitle = "#ffffff"; + SelectedDesc = "#ffffff"; + SelectedTitle = "#ffffff"; + SelectedBorder = "#ffffff"; + SelectedDescBorder = "#ffffff"; + TitleFore = "#ffffff"; + Titleback = "#434C5E"; + StatusMsg = "#ffffff"; + PinIndicatorColor = "#ff0000"; + }; + ''; + + description = '' + Configuration written to + {file}`$XDG_CONFIG_HOME/clipse/custom_theme.json`. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "services.clipse" pkgs + lib.platforms.linux) + ]; + + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + + xdg.configFile."clipse/config.json".source = + jsonFormat.generate "settings" { + allowDuplicates = cfg.allowDuplicates; + historyFile = "clipboard_history.json"; + maxHistory = cfg.historySize; + logFile = "clipse.log"; + themeFile = "custom_theme.json"; + tempDir = "tmp_files"; + keyBindings = cfg.keyBindings; + imageDisplay = cfg.imageDisplay; + }; + + xdg.configFile."clipse/custom_theme.json".source = + jsonFormat.generate "theme" cfg.theme; + + systemd.user.services.clipse = + lib.mkIf (pkgs.stdenv.isLinux && (cfg.package != null)) { + Unit = { + Description = "Clipse listener"; + PartOf = [ "graphical-session.target" ]; + After = [ "graphical-session.target" ]; + }; + + Service = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${cfg.package}/bin/clipse -listen"; + }; + + Install = { WantedBy = [ cfg.systemdTarget ]; }; + }; + }; +} diff --git a/modules/services/darkman.nix b/modules/services/darkman.nix index b399dad86..93aafda98 100644 --- a/modules/services/darkman.nix +++ b/modules/services/darkman.nix @@ -48,7 +48,7 @@ in { darkman, a tool that automatically switches dark-mode on and off based on the time of the day''; - package = mkPackageOption pkgs "darkman" { }; + package = mkPackageOption pkgs "darkman" { nullable = true; }; settings = mkOption { type = types.submodule { freeformType = yamlFormat.type; }; @@ -76,7 +76,7 @@ in { (hm.assertions.assertPlatform "services.darkman" pkgs platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile = { "darkman/config.yaml" = mkIf (cfg.settings != { }) { @@ -91,7 +91,7 @@ in { (generateScripts "light-mode.d" cfg.lightModeScripts)) ]; - systemd.user.services.darkman = { + systemd.user.services.darkman = lib.mkIf (cfg.package != null) { Unit = { Description = "Darkman system service"; Documentation = "man:darkman(1)"; diff --git a/modules/services/davmail.nix b/modules/services/davmail.nix new file mode 100644 index 000000000..a58a2fea7 --- /dev/null +++ b/modules/services/davmail.nix @@ -0,0 +1,128 @@ +{ config, lib, pkgs, ... }: +let + + inherit (lib) + mapAttrsRecursive mkDefault mkEnableOption mkIf mkOption optionalAttrs + types; + + cfg = config.services.davmail; + + javaProperties = pkgs.formats.javaProperties { }; + + settingsFile = javaProperties.generate "davmail.properties" cfg.settings; + +in { + + meta.maintainers = [ lib.hm.maintainers.bmrips ]; + + options.services.davmail = { + + enable = mkEnableOption "DavMail, an MS Exchange gateway."; + + package = lib.mkPackageOption pkgs "davmail" { }; + + imitateOutlook = mkOption { + type = types.bool; + default = false; + description = "Whether DavMail pretends to be Outlook."; + example = true; + }; + + settings = mkOption { + type = javaProperties.type; + default = { }; + description = '' + Davmail configuration. Refer to + + and + for details on supported values. + ''; + example = { + "davmail.url" = "https://outlook.office365.com/EWS/Exchange.asmx"; + "davmail.allowRemote" = true; + "davmail.imapPort" = 55555; + "davmail.bindAddress" = "10.0.1.2"; + "davmail.smtpSaveInSent" = true; + "davmail.folderSizeLimit" = 10; + "davmail.caldavAutoSchedule" = false; + "log4j.logger.rootLogger" = "DEBUG"; + }; + }; + + }; + + config = mkIf cfg.enable { + + assertions = [{ + assertion = pkgs.stdenv.hostPlatform.isLinux; + message = "The DavMail service is only available on Linux."; + }]; + + services.davmail.settings = mapAttrsRecursive (_: mkDefault) { + "davmail.server" = true; + "davmail.disableUpdateCheck" = true; + "davmail.logFilePath" = "${config.xdg.stateHome}/davmail.log"; + "davmail.logFileSize" = "1MB"; + "davmail.mode" = "auto"; + "davmail.url" = "https://outlook.office365.com/EWS/Exchange.asmx"; + "davmail.caldavPort" = 1080; + "davmail.imapPort" = 1143; + "davmail.ldapPort" = 1389; + "davmail.popPort" = 1110; + "davmail.smtpPort" = 1025; + + # The token file path is set because, otherwise, if oauth.persistToken + # is enabled, DavMail would attempt to write the token into generated + # configuration which lays in the Nix store. + "davmail.oauth.tokenFilePath" = "${config.xdg.stateHome}/davmail-tokens"; + + "log4j.logger.davmail" = "WARN"; + "log4j.logger.httpclient.wire" = "WARN"; + "log4j.logger.org.apache.commons.httpclient" = "WARN"; + "log4j.rootLogger" = "WARN"; + } // optionalAttrs cfg.imitateOutlook { + "davmail.oauth.clientId" = "d3590ed6-52b3-4102-aeff-aad2292ab01c"; + "davmail.oauth.redirectUri" = "urn:ietf:wg:oauth:2.0:oob"; + }; + + systemd.user.services.davmail = { + Unit = { + Description = "DavMail POP/IMAP/SMTP Exchange Gateway"; + After = [ "graphical-session.target" "network.target" ]; + }; + Install.WantedBy = [ "graphical-session.target" ]; + Service = { + Type = "simple"; + ExecStart = "${lib.getExe cfg.package} ${settingsFile}"; + Restart = "on-failure"; + + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + LockPersonality = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectSystem = "strict"; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + RemoveIPC = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = "@system-service"; + SystemCallErrorNumber = "EPERM"; + UMask = "0077"; + }; + }; + + home.packages = [ cfg.package ]; + }; +} diff --git a/modules/services/devilspie2.nix b/modules/services/devilspie2.nix index fa77153e7..ab61e9778 100644 --- a/modules/services/devilspie2.nix +++ b/modules/services/devilspie2.nix @@ -36,7 +36,7 @@ in { Service.ExecStart = "${pkgs.devilspie2}/bin/devilspie2"; Unit = { Description = "devilspie2"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; Install.WantedBy = [ "graphical-session.target" ]; diff --git a/modules/services/easyeffects.nix b/modules/services/easyeffects.nix index fd5e4b404..d45c5d8ee 100644 --- a/modules/services/easyeffects.nix +++ b/modules/services/easyeffects.nix @@ -1,18 +1,63 @@ { config, lib, pkgs, ... }: - -with lib; - let + inherit (lib) literalExpression mkOption types; cfg = config.services.easyeffects; - presetOpts = optionalString (cfg.preset != "") "--load-preset ${cfg.preset}"; + presetOpts = + lib.optionalString (cfg.preset != "") "--load-preset ${cfg.preset}"; + jsonFormat = pkgs.formats.json { }; + + presetType = let baseType = types.attrsOf jsonFormat.type; + in baseType // { + check = v: + baseType.check v + && lib.elem (lib.head (lib.attrNames v)) [ "input" "output" ]; + description = "EasyEffects input or output JSON preset"; + }; + + presetOptionType = mkOption { + type = types.nullOr (types.attrsOf presetType); + default = { }; + description = '' + List of presets to import to easyeffects. + Presets are written to input and output folder in `$XDG_CONFIG_HOME/easyeffects`. + Top level block (input/output) determines the folder the file is written to. + + See community presets at: + https://github.com/wwmm/easyeffects/wiki/Community-Presets + ''; + example = literalExpression '' + { + my-preset = { + input = { + blocklist = [ + + ]; + "plugins_order" = [ + "rnnoise#0" + ]; + "rnnoise#0" = { + bypass = false; + "enable-vad" = false; + "input-gain" = 0.0; + "model-path" = ""; + "output-gain" = 0.0; + release = 20.0; + "vad-thres" = 50.0; + wet = 0.0; + }; + }; + }; + }; + ''; + }; in { - meta.maintainers = [ maintainers.fufexan ]; + meta.maintainers = with lib.maintainers; [ fufexan hausken ]; options.services.easyeffects = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' Easyeffects daemon. Note, it is necessary to add ```nix @@ -35,23 +80,33 @@ in { Will likely need to launch easyeffects to initially create preset. ''; }; + + extraPresets = presetOptionType; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ - (hm.assertions.assertPlatform "services.easyeffects" pkgs platforms.linux) + (lib.hm.assertions.assertPlatform "services.easyeffects" pkgs + lib.platforms.linux) ]; - # running easyeffects will just attach itself to gapplication service - # at-spi2-core is to minimize journalctl noise of: + # Running easyeffects will just attach itself to `gapplication` service + # at-spi2-core is to minimize `journalctl` noise of: # "AT-SPI: Error retrieving accessibility bus address: org.freedesktop.DBus.Error.ServiceUnknown: The name org.a11y.Bus was not provided by any .service files" home.packages = with pkgs; [ cfg.package at-spi2-core ]; + xdg.configFile = lib.mkIf (cfg.extraPresets != { }) (lib.mapAttrs' (k: v: + # Assuming only one of either input or output block is defined, having both in same file not seem to be supported by the application since it separates it by folder + let folder = builtins.head (builtins.attrNames v); + in lib.nameValuePair "easyeffects/${folder}/${k}.json" { + source = jsonFormat.generate "${folder}-${k}.json" v; + }) cfg.extraPresets); + systemd.user.services.easyeffects = { Unit = { Description = "Easyeffects daemon"; Requires = [ "dbus.service" ]; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" "pipewire.service" ]; }; diff --git a/modules/services/flameshot.nix b/modules/services/flameshot.nix index ebdfd0067..b35f518b3 100644 --- a/modules/services/flameshot.nix +++ b/modules/services/flameshot.nix @@ -56,7 +56,7 @@ in { Unit = { Description = "Flameshot screenshot tool"; Requires = [ "tray.target" ]; - After = [ "graphical-session-pre.target" "tray.target" ]; + After = [ "graphical-session.target" "tray.target" ]; PartOf = [ "graphical-session.target" ]; X-Restart-Triggers = mkIf (cfg.settings != { }) [ "${iniFile}" ]; }; diff --git a/modules/services/fusuma.nix b/modules/services/fusuma.nix index 17d8b1431..aa81320b1 100644 --- a/modules/services/fusuma.nix +++ b/modules/services/fusuma.nix @@ -119,7 +119,7 @@ in { systemd.user.services.fusuma = { Unit = { Description = "Fusuma services"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/glance.nix b/modules/services/glance.nix index fa4f1a8d7..7abe17e2c 100644 --- a/modules/services/glance.nix +++ b/modules/services/glance.nix @@ -59,11 +59,11 @@ in { lib.platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."glance/glance.yml".source = settingsFile; - systemd.user.services.glance = { + systemd.user.services.glance = lib.mkIf (cfg.package != null) { Unit = { Description = "Glance feed dashboard server"; PartOf = [ "graphical-session.target" ]; diff --git a/modules/services/gpg-agent.nix b/modules/services/gpg-agent.nix index f32d85af3..48f1ae8c6 100644 --- a/modules/services/gpg-agent.nix +++ b/modules/services/gpg-agent.nix @@ -300,7 +300,7 @@ in { ''; programs.bash.initExtra = mkIf cfg.enableBashIntegration gpgInitStr; - programs.zsh.initExtra = mkIf cfg.enableZshIntegration gpgZshInitStr; + programs.zsh.initContent = mkIf cfg.enableZshIntegration gpgZshInitStr; programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration gpgFishInitStr; diff --git a/modules/services/grobi.nix b/modules/services/grobi.nix index 9031089c9..c8a3b1412 100644 --- a/modules/services/grobi.nix +++ b/modules/services/grobi.nix @@ -79,7 +79,7 @@ in { systemd.user.services.grobi = { Unit = { Description = "grobi display auto config daemon"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/gromit-mpx.nix b/modules/services/gromit-mpx.nix index f46eddb39..142c49814 100644 --- a/modules/services/gromit-mpx.nix +++ b/modules/services/gromit-mpx.nix @@ -215,7 +215,7 @@ in { systemd.user.services.gromit-mpx = { Unit = { Description = "Gromit-MPX"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; X-Restart-Triggers = [ "${config.xdg.configFile."gromit-mpx.cfg".source}" diff --git a/modules/services/hypridle.nix b/modules/services/hypridle.nix index 155f4ac36..2778bff66 100644 --- a/modules/services/hypridle.nix +++ b/modules/services/hypridle.nix @@ -6,7 +6,7 @@ in { options.services.hypridle = { enable = lib.mkEnableOption "Hypridle, Hyprland's idle daemon"; - package = lib.mkPackageOption pkgs "hypridle" { }; + package = lib.mkPackageOption pkgs "hypridle" { nullable = true; }; settings = lib.mkOption { type = with lib.types; @@ -70,7 +70,7 @@ in { }; }; - systemd.user.services.hypridle = { + systemd.user.services.hypridle = lib.mkIf (cfg.package != null) { Install = { WantedBy = [ config.wayland.systemd.target ]; }; Unit = { diff --git a/modules/services/hyprpaper.nix b/modules/services/hyprpaper.nix index 03eabf94c..ba64e2372 100644 --- a/modules/services/hyprpaper.nix +++ b/modules/services/hyprpaper.nix @@ -6,7 +6,7 @@ in { options.services.hyprpaper = { enable = lib.mkEnableOption "Hyprpaper, Hyprland's wallpaper daemon"; - package = lib.mkPackageOption pkgs "hyprpaper" { }; + package = lib.mkPackageOption pkgs "hyprpaper" { nullable = true; }; settings = lib.mkOption { type = with lib.types; @@ -64,7 +64,7 @@ in { }; }; - systemd.user.services.hyprpaper = { + systemd.user.services.hyprpaper = lib.mkIf (cfg.package != null) { Install = { WantedBy = [ config.wayland.systemd.target ]; }; Unit = { diff --git a/modules/services/hyprpolkitagent.nix b/modules/services/hyprpolkitagent.nix new file mode 100644 index 000000000..437c65e98 --- /dev/null +++ b/modules/services/hyprpolkitagent.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: +let + inherit (lib) mkEnableOption mkPackageOption mkIf maintainers; + cfg = config.services.hyprpolkitagent; +in { + meta.maintainers = with maintainers; [ bobvanderlinden khaneliman ]; + + options = { + services.hyprpolkitagent = { + enable = mkEnableOption "Hyprland Policykit Agent"; + package = mkPackageOption pkgs "hyprpolkitagent" { }; + }; + }; + + config = mkIf cfg.enable { + systemd.user.services.hyprpolkitagent = { + Unit = { + Description = "Hyprland PolicyKit Agent"; + PartOf = [ config.wayland.systemd.target ]; + After = [ config.wayland.systemd.target ]; + }; + + Install = { WantedBy = [ config.wayland.systemd.target ]; }; + + Service = { ExecStart = "${cfg.package}/libexec/hyprpolkitagent"; }; + }; + }; +} diff --git a/modules/services/imapnotify-accounts.nix b/modules/services/imapnotify-accounts.nix index e437f94e3..1a6fbf58a 100644 --- a/modules/services/imapnotify-accounts.nix +++ b/modules/services/imapnotify-accounts.nix @@ -1,10 +1,8 @@ { pkgs, lib, ... }: - -with lib; - -{ +let inherit (lib) mkOption types; +in { options.imapnotify = { - enable = mkEnableOption "imapnotify"; + enable = lib.mkEnableOption "imapnotify"; onNotify = mkOption { type = with types; either str (attrsOf str); @@ -30,10 +28,16 @@ with lib; description = "IMAP folders to watch."; }; + extraArgs = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "-wait 1" ]; + description = "Extra arguments to pass to goimapnotify."; + }; + extraConfig = mkOption { type = let jsonFormat = pkgs.formats.json { }; in jsonFormat.type; default = { }; - example = { wait = 10; }; description = "Additional configuration to add for this account."; }; }; diff --git a/modules/services/imapnotify.nix b/modules/services/imapnotify.nix index a52b86e97..bf8fefd39 100644 --- a/modules/services/imapnotify.nix +++ b/modules/services/imapnotify.nix @@ -23,7 +23,10 @@ let Service = { # Use the nix store path for config to ensure service restarts when it changes ExecStart = - "${getExe cfg.package} -conf '${genAccountConfig account}'"; + "${getExe cfg.package} -conf '${genAccountConfig account}'" + " ${ + lib.optionalString (account.imapnotify.extraArgs != [ ]) + (toString account.imapnotify.extraArgs) + }"; Restart = "always"; RestartSec = 30; Type = "simple"; diff --git a/modules/services/jankyborders.nix b/modules/services/jankyborders.nix new file mode 100644 index 000000000..77e4a5e67 --- /dev/null +++ b/modules/services/jankyborders.nix @@ -0,0 +1,83 @@ +{ config, lib, pkgs, ... }: +let cfg = config.services.jankyborders; +in { + meta.maintainers = [ lib.maintainers.khaneliman ]; + + options.services.jankyborders = { + enable = lib.mkEnableOption "jankyborders"; + + package = lib.mkPackageOption pkgs "jankyborders" { }; + + errorLogFile = lib.mkOption { + type = with lib.types; nullOr (either path str); + defaultText = lib.literalExpression + "\${config.home.homeDirectory}/Library/Logs/jankyborders/err.log"; + example = "/Users/khaneliman/Library/Logs/jankyborders.log"; + description = "Absolute path to log all stderr output."; + }; + + outLogFile = lib.mkOption { + type = with lib.types; nullOr (either path str); + defaultText = lib.literalExpression + "\${config.home.homeDirectory}/Library/Logs/jankyborders/out.log"; + example = "/Users/khaneliman/Library/Logs/jankyborders.log"; + description = "Absolute path to log all stdout output."; + }; + + settings = lib.mkOption { + type = with lib.types; attrsOf anything; + default = { }; + example = lib.literalExpression '' + { + style=round; + width=6.0; + hidpi="off"; + active_color="0xffe2e2e3"; + inactive_color="0xff414550"; + } + ''; + description = '' + Configuration settings to passed to `borders` in + {file}`$XDG_CONFIG_HOME/borders/bordersc`. See + + for the documentation. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "services.jankyborders" pkgs + lib.platforms.darwin) + ]; + + home.packages = [ cfg.package ]; + + launchd.agents.jankyborders = { + enable = true; + config = { + ProgramArguments = [ (lib.getExe cfg.package) ]; + ProcessType = "Interactive"; + KeepAlive = true; + RunAtLoad = true; + StandardErrorPath = cfg.errorLogFile; + StandardOutPath = cfg.outLogFile; + }; + }; + + services.jankyborders = { + errorLogFile = lib.mkOptionDefault + "${config.home.homeDirectory}/Library/Logs/borders/borders.err.log"; + outLogFile = lib.mkOptionDefault + "${config.home.homeDirectory}/Library/Logs/borders/borders.out.log"; + }; + + xdg.configFile."borders/bordersrc".source = + pkgs.writeShellScript "bordersrc" '' + options=( + ${lib.generators.toKeyValue { indent = " "; } cfg.settings}) + + ${lib.getExe cfg.package} "''${options[@]}" + ''; + }; +} diff --git a/modules/services/kdeconnect.nix b/modules/services/kdeconnect.nix index f30d79fc5..3e6822744 100644 --- a/modules/services/kdeconnect.nix +++ b/modules/services/kdeconnect.nix @@ -40,7 +40,7 @@ in { Unit = { Description = "Adds communication between your desktop and your smartphone"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; @@ -69,7 +69,7 @@ in { Unit = { Description = "kdeconnect-indicator"; After = [ - "graphical-session-pre.target" + "graphical-session.target" "polybar.service" "taffybar.service" "stalonetray.service" diff --git a/modules/services/keynav.nix b/modules/services/keynav.nix index d83252e53..7ba5ce2e0 100644 --- a/modules/services/keynav.nix +++ b/modules/services/keynav.nix @@ -18,7 +18,7 @@ in { systemd.user.services.keynav = { Unit = { Description = "keynav"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/librespot.nix b/modules/services/librespot.nix new file mode 100644 index 000000000..f8e19c0a8 --- /dev/null +++ b/modules/services/librespot.nix @@ -0,0 +1,88 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) types; + + # Like lib.mapAttrsToList, but concatenate the results + concatMapAttrsToList = f: attrs: + builtins.concatMap (name: f name attrs.${name}) (builtins.attrNames attrs); + + cfg = config.services.librespot; +in { + options.services.librespot = { + enable = lib.mkEnableOption "Librespot (Spotify Connect speaker daemon)"; + + package = lib.mkPackageOption pkgs "librespot" { }; + + settings = lib.mkOption { + description = '' + Command-line arguments to pass to librespot. + + Boolean values render as a flag if true, and nothing if false. + Null values are ignored. + All other values are rendered as options with an argument. + ''; + type = types.submodule { + freeformType = let t = types; + in t.attrsOf (t.nullOr (t.oneOf [ t.bool t.str t.int t.path ])); + + options = { + cache = lib.mkOption { + default = "${config.xdg.cacheHome}/librespot"; + defaultText = "$XDG_CACHE_HOME/librespot"; + type = types.nullOr types.path; + description = + "Path to a directory where files will be cached after downloading."; + }; + + system-cache = lib.mkOption { + default = "${config.xdg.stateHome}/librespot"; + defaultText = "$XDG_STATE_HOME/librespot"; + type = types.nullOr types.path; + description = + "Path to a directory where system files (credentials, volume) will be cached."; + }; + }; + }; + default = { }; + }; + + args = lib.mkOption { + type = types.listOf types.str; + internal = true; + description = '' + Command-line arguments to pass to the service. + + This is generated from {option}`services.librespot.settings`. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + services.librespot = { + args = concatMapAttrsToList (k: v: + if v == null || v == false then + [ ] + else if v == true then + [ "--${k}" ] + else + [ "--${k}=${toString v}" ]) cfg.settings; + }; + + home.packages = [ cfg.package ]; + + systemd.user.services.librespot = { + Unit = { Description = "Librespot (an open source Spotify client)"; }; + + Install.WantedBy = [ "default.target" ]; + + Service = { + ExecStart = pkgs.writeShellScript "librespot" '' + exec '${cfg.package}/bin/librespot' ${lib.escapeShellArgs cfg.args} + ''; + Restart = "always"; + RestartSec = 12; + }; + }; + }; +} diff --git a/modules/services/listenbrainz-mpd.nix b/modules/services/listenbrainz-mpd.nix index 3cc242216..3ccb75411 100644 --- a/modules/services/listenbrainz-mpd.nix +++ b/modules/services/listenbrainz-mpd.nix @@ -15,7 +15,7 @@ in { options.services.listenbrainz-mpd = { enable = mkEnableOption "listenbrainz-mpd"; - package = mkPackageOption pkgs "listenbrainz-mpd" { }; + package = mkPackageOption pkgs "listenbrainz-mpd" { nullable = true; }; settings = mkOption { type = tomlFormat.type; @@ -29,7 +29,7 @@ in { }; config = mkIf cfg.enable { - systemd.user.services."listenbrainz-mpd" = { + systemd.user.services."listenbrainz-mpd" = lib.mkIf (cfg.package != null) { Unit = { Description = "ListenBrainz submission client for MPD"; Documentation = "https://codeberg.org/elomatreb/listenbrainz-mpd"; diff --git a/modules/services/lxqt-policykit-agent.nix b/modules/services/lxqt-policykit-agent.nix new file mode 100644 index 000000000..85250ea29 --- /dev/null +++ b/modules/services/lxqt-policykit-agent.nix @@ -0,0 +1,29 @@ +{ config, lib, pkgs, ... }: +let + inherit (lib) + mkEnableOption mkPackageOption types literalExpression mkIf maintainers; + cfg = config.services.lxqt-policykit-agent; +in { + meta.maintainers = [ maintainers.bobvanderlinden ]; + + options = { + services.lxqt-policykit-agent = { + enable = mkEnableOption "LXQT Policykit Agent"; + package = mkPackageOption pkgs [ "lxqt" "lxqt-policykit" ] { }; + }; + }; + + config = mkIf cfg.enable { + systemd.user.services.lxqt-policykit-agent = { + Unit = { + Description = "LXQT PolicyKit Agent"; + After = [ "graphical-session-pre.target" ]; + PartOf = [ "graphical-session.target" ]; + }; + + Install = { WantedBy = [ "graphical-session.target" ]; }; + + Service = { ExecStart = "${cfg.package}/bin/lxqt-policykit-agent"; }; + }; + }; +} diff --git a/modules/services/macos-remap-keys/default.nix b/modules/services/macos-remap-keys/default.nix new file mode 100644 index 000000000..0c0d2575d --- /dev/null +++ b/modules/services/macos-remap-keys/default.nix @@ -0,0 +1,72 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.services.macos-remap-keys; + keytables = import ./keytables.nix { inherit lib; }; + + keyToHIDCode = table: key: keytables.${table}.${key}; + + # Note: hidutil requires HIDKeyboardModifierMapping values to be in hexadecimal + # format rather than decimal JSON. Using hex strings instead of numbers will + # crash macOS. + makeMapping = table: from: to: + '' + { "HIDKeyboardModifierMappingSrc": ${ + keyToHIDCode table from + }, "HIDKeyboardModifierMappingDst": ${keyToHIDCode table to} }''; + + makeMappingsList = table: mappings: + lib.mapAttrsToList (from: to: makeMapping table from to) mappings; + + allMappings = (makeMappingsList "keyboard" (cfg.keyboard or { })) + ++ (makeMappingsList "keypad" (cfg.keypad or { })); + + allMappingsString = lib.concatStringsSep ", " allMappings; + propertyString = ''{ "UserKeyMapping": [ ${allMappingsString} ] }''; +in { + meta.maintainers = [ lib.maintainers.WeetHet ]; + + options.services.macos-remap-keys = { + enable = lib.mkEnableOption "macOS key remapping service"; + + keyboard = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = { }; + example = { + Capslock = "Escape"; + SquareBracketOpen = "SquareBracketClose"; + }; + description = "Mapping of keyboard keys to remap"; + }; + + keypad = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = { }; + example = { + Enter = "Equal"; + Plus = "Minus"; + }; + description = "Mapping of keypad keys to remap"; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "services.macos-remap-keys" pkgs + lib.platforms.darwin) + ]; + home.activation.macosRemapKeys = + lib.hm.dag.entryAfter [ "writeBoundary" ] '' + run --silence /usr/bin/hidutil property --set '${propertyString}' + ''; + + launchd.agents.remap-keys = { + enable = true; + config = { + ProgramArguments = + [ "/usr/bin/hidutil" "property" "--set" propertyString ]; + KeepAlive.SuccessfulExit = false; + RunAtLoad = true; + }; + }; + }; +} diff --git a/modules/services/macos-remap-keys/keytables.nix b/modules/services/macos-remap-keys/keytables.nix new file mode 100644 index 000000000..a44bb4ece --- /dev/null +++ b/modules/services/macos-remap-keys/keytables.nix @@ -0,0 +1,139 @@ +{ lib }: +let + letters = let + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + lettersList = lib.stringToCharacters alphabet; + indices = builtins.genList (i: i + 4) 26; + in lib.listToAttrs (lib.zipListsWith (letter: index: { + name = letter; + value = "0x${lib.toHexString index}"; + }) lettersList indices); + + numbers = { + One = "0x1E"; + Two = "0x1F"; + Three = "0x20"; + Four = "0x21"; + Five = "0x22"; + Six = "0x23"; + Seven = "0x24"; + Eight = "0x25"; + Nine = "0x26"; + Zero = "0x27"; + }; + + specialKeys = { + Enter = "0x28"; + Escape = "0x29"; + Backspace = "0x2A"; + Tab = "0x2B"; + Spacebar = "0x2C"; + Minus = "0x2D"; + Equal = "0x2E"; + SquareBracketOpen = "0x2F"; + SquareBracketClose = "0x30"; + Backslash = "0x31"; + Hash = "0x32"; + Semicolon = "0x33"; + SingleQuote = "0x34"; + GraveAccent = "0x35"; + Comma = "0x36"; + Dot = "0x37"; + Slash = "0x38"; + Capslock = "0x39"; + }; + + fKeys1To12 = { + F1 = "0x3A"; + F2 = "0x3B"; + F3 = "0x3C"; + F4 = "0x3D"; + F5 = "0x3E"; + F6 = "0x3F"; + F7 = "0x40"; + F8 = "0x41"; + F9 = "0x42"; + F10 = "0x43"; + F11 = "0x44"; + F12 = "0x45"; + }; + + fKeys13To24 = { + F13 = "0x68"; + F14 = "0x69"; + F15 = "0x6A"; + F16 = "0x6B"; + F17 = "0x6C"; + F18 = "0x6D"; + F19 = "0x6E"; + F20 = "0x6F"; + F21 = "0x70"; + F22 = "0x71"; + F23 = "0x72"; + F24 = "0x73"; + }; + + navigationKeys = { + PrintScreen = "0x46"; + ScrollLock = "0x47"; + Pause = "0x48"; + Insert = "0x49"; + Home = "0x4A"; + PageUp = "0x4B"; + ForwardDelete = "0x4C"; + End = "0x4D"; + PageDown = "0x4E"; + RightArrow = "0x4F"; + LeftArrow = "0x50"; + DownArrow = "0x51"; + UpArrow = "0x52"; + NumLock = "0x53"; + }; + + modifierKeys = { + Control = "0xE0"; + Shift = "0xE1"; + Option = "0xE2"; + Command = "0xE3"; + RightControl = "0xE4"; + RightShift = "0xE5"; + RightOption = "0xE6"; + RightCommand = "0xE7"; + }; + + keypadKeys = { + Slash = "0x54"; + Asterisk = "0x55"; + Minus = "0x56"; + Plus = "0x57"; + Enter = "0x58"; + One = "0x59"; + Two = "0x5A"; + Three = "0x5B"; + Four = "0x5C"; + Five = "0x5D"; + Six = "0x5E"; + Seven = "0x5F"; + Eight = "0x60"; + Nine = "0x61"; + Zero = "0x62"; + Dot = "0x63"; + BashSlash = "0x64"; + Application = "0x65"; + Power = "0x66"; + Equal = "0x67"; + }; + + mapToInt = keyPage: attrs: + lib.mapAttrs (name: value: + let keycode = lib.fromHexString (lib.removePrefix "0x" value); + in "0x${lib.toHexString (keyPage + keycode)}") attrs; + + page7Keys = mapToInt (lib.fromHexString "700000000") (letters // numbers + // specialKeys // fKeys1To12 // fKeys13To24 // navigationKeys + // modifierKeys); + pageFFKeys = mapToInt (lib.fromHexString "FF00000000") { Fn = "0x3"; }; +in { + keyboard = page7Keys // pageFFKeys; + keypad = mapToInt keypadKeys; +} diff --git a/modules/services/megasync.nix b/modules/services/megasync.nix index 03eab490a..57af06077 100644 --- a/modules/services/megasync.nix +++ b/modules/services/megasync.nix @@ -1,23 +1,24 @@ { config, lib, pkgs, ... }: - -with lib; - -let - - cfg = config.services.megasync; - +let cfg = config.services.megasync; in { - meta.maintainers = [ maintainers.GaetanLepage ]; + meta.maintainers = [ lib.maintainers.GaetanLepage ]; options = { services.megasync = { - enable = mkEnableOption "Megasync client"; + enable = lib.mkEnableOption "Megasync client"; - package = mkPackageOption pkgs "megasync" { }; + package = lib.mkPackageOption pkgs "megasync" { }; + + forceWayland = lib.mkOption { + type = lib.types.bool; + default = false; + example = true; + description = "Force Megasync to run on wayland"; + }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ (lib.hm.assertions.assertPlatform "services.megasync" pkgs lib.platforms.linux) @@ -34,7 +35,11 @@ in { Install = { WantedBy = [ "graphical-session.target" ]; }; - Service = { ExecStart = "${cfg.package}/bin/megasync"; }; + Service = { + Environment = + lib.optionals cfg.forceWayland [ "DO_NOT_UNSET_XDG_SESSION_TYPE=1" ]; + ExecStart = lib.getExe cfg.package; + }; }; }; } diff --git a/modules/services/mpd-discord-rpc.nix b/modules/services/mpd-discord-rpc.nix index 8996051a5..dfe408921 100644 --- a/modules/services/mpd-discord-rpc.nix +++ b/modules/services/mpd-discord-rpc.nix @@ -50,7 +50,7 @@ in { Unit = { Description = "Discord Rich Presence for MPD"; Documentation = "https://github.com/JakeStanger/mpd-discord-rpc"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; Service = { diff --git a/modules/services/mpd.nix b/modules/services/mpd.nix index 8787ad667..a1df5640a 100644 --- a/modules/services/mpd.nix +++ b/modules/services/mpd.nix @@ -1,38 +1,11 @@ { config, lib, pkgs, ... }: - -with lib; - let - - name = "mpd"; + inherit (lib) mkIf mkOption types; cfg = config.services.mpd; - - mpdConf = pkgs.writeText "mpd.conf" '' - music_directory "${cfg.musicDirectory}" - playlist_directory "${cfg.playlistDirectory}" - ${lib.optionalString (cfg.dbFile != null) '' - db_file "${cfg.dbFile}" - ''} - state_file "${cfg.dataDir}/state" - sticker_file "${cfg.dataDir}/sticker.sql" - - ${optionalString (cfg.network.listenAddress != "any") - ''bind_to_address "${cfg.network.listenAddress}"''} - ${optionalString (cfg.network.port != 6600) - ''port "${toString cfg.network.port}"''} - - ${cfg.extraConfig} - ''; - in { - - ###### interface - options = { - services.mpd = { - enable = mkOption { type = types.bool; default = false; @@ -52,7 +25,7 @@ in { musicDirectory = mkOption { type = with types; either path str; - defaultText = literalExpression '' + defaultText = lib.literalExpression '' ''${home.homeDirectory}/music if state version < 22.11 ''${xdg.userDirs.music} if xdg.userDirs.enable == true undefined otherwise @@ -100,7 +73,7 @@ in { dataDir = mkOption { type = types.path; - default = "${config.xdg.dataHome}/${name}"; + default = "${config.xdg.dataHome}/mpd"; defaultText = "$XDG_DATA_HOME/mpd"; apply = toString; # Prevent copies to Nix store. description = '' @@ -113,8 +86,10 @@ in { startWhenNeeded = mkOption { type = types.bool; default = false; + visible = pkgs.stdenv.hostPlatform.isLinux; + readOnly = pkgs.stdenv.hostPlatform.isDarwin; description = '' - Enable systemd socket activation. + Enable systemd socket activation. This is only supported on Linux. ''; }; @@ -149,72 +124,97 @@ in { ''; }; }; - }; - ###### implementation + config = let + mpdConf = pkgs.writeText "mpd.conf" ('' + music_directory "${cfg.musicDirectory}" + playlist_directory "${cfg.playlistDirectory}" + '' + lib.optionalString (cfg.dbFile != null) '' + db_file "${cfg.dbFile}" + '' + lib.optionalString (pkgs.stdenv.hostPlatform.isDarwin) '' + log_file "${config.home.homeDirectory}/Library/Logs/mpd/log.txt" + '' + '' + state_file "${cfg.dataDir}/state" + sticker_file "${cfg.dataDir}/sticker.sql" - config = mkIf cfg.enable { - assertions = [ - (lib.hm.assertions.assertPlatform "services.mpd" pkgs lib.platforms.linux) - ]; + '' + lib.optionalString (cfg.network.listenAddress != "any") '' + bind_to_address "${cfg.network.listenAddress}" + '' + lib.optionalString (cfg.network.port != 6600) '' + port "${toString cfg.network.port}" + '' + lib.optionalString (cfg.extraConfig != "") '' + ${cfg.extraConfig} + ''); + in mkIf cfg.enable { + home.packages = [ cfg.package ]; - services.mpd = mkMerge [ - (mkIf (versionAtLeast config.home.stateVersion "22.11" + services.mpd = lib.mkMerge [ + (mkIf (lib.versionAtLeast config.home.stateVersion "22.11" && config.xdg.userDirs.enable) { - musicDirectory = mkOptionDefault config.xdg.userDirs.music; + musicDirectory = lib.mkOptionDefault config.xdg.userDirs.music; }) - (mkIf (versionOlder config.home.stateVersion "22.11") { - musicDirectory = mkOptionDefault "${config.home.homeDirectory}/music"; + (mkIf (lib.versionOlder config.home.stateVersion "22.11") { + musicDirectory = + lib.mkOptionDefault "${config.home.homeDirectory}/music"; }) ]; - systemd.user.services.mpd = { - Unit = mkMerge [ - { - Description = "Music Player Daemon"; - After = [ "network.target" "sound.target" ]; - } + systemd.user = lib.mkIf pkgs.stdenv.hostPlatform.isLinux { + services.mpd = { + Unit = lib.mkMerge [ + { + Description = "Music Player Daemon"; + After = [ "network.target" "sound.target" ]; + } - (mkIf cfg.network.startWhenNeeded { - Requires = [ "mpd.socket" ]; - After = [ "mpd.socket" ]; - }) - ]; + (mkIf cfg.network.startWhenNeeded { + Requires = [ "mpd.socket" ]; + After = [ "mpd.socket" ]; + }) + ]; - Install = mkIf (!cfg.network.startWhenNeeded) { - WantedBy = [ "default.target" ]; + Install = mkIf (!cfg.network.startWhenNeeded) { + WantedBy = [ "default.target" ]; + }; + + Service = { + Environment = [ "PATH=${config.home.profileDirectory}/bin" ]; + ExecStart = "${cfg.package}/bin/mpd --no-daemon ${mpdConf} ${ + lib.escapeShellArgs cfg.extraArgs + }"; + Type = "notify"; + ExecStartPre = '' + ${pkgs.bash}/bin/bash -c "${pkgs.coreutils}/bin/mkdir -p '${cfg.dataDir}' '${cfg.playlistDirectory}'"''; + }; }; - Service = { - Environment = [ "PATH=${config.home.profileDirectory}/bin" ]; - ExecStart = "${cfg.package}/bin/mpd --no-daemon ${mpdConf} ${ - escapeShellArgs cfg.extraArgs - }"; - Type = "notify"; - ExecStartPre = '' - ${pkgs.bash}/bin/bash -c "${pkgs.coreutils}/bin/mkdir -p '${cfg.dataDir}' '${cfg.playlistDirectory}'"''; + sockets.mpd = mkIf cfg.network.startWhenNeeded { + Socket = { + ListenStream = let + listen = if cfg.network.listenAddress == "any" then + toString cfg.network.port + else + "${cfg.network.listenAddress}:${toString cfg.network.port}"; + in [ listen "%t/mpd/socket" ]; + + Backlog = 5; + KeepAlive = true; + }; + + Install = { WantedBy = [ "sockets.target" ]; }; }; }; - systemd.user.sockets.mpd = mkIf cfg.network.startWhenNeeded { - Socket = { - ListenStream = let - listen = if cfg.network.listenAddress == "any" then - toString cfg.network.port - else - "${cfg.network.listenAddress}:${toString cfg.network.port}"; - in [ listen "%t/mpd/socket" ]; - - Backlog = 5; + launchd.agents.mpd = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin { + enable = true; + config = { + ProgramArguments = + [ (lib.getExe cfg.package) "--no-daemon" "${mpdConf}" ] + ++ cfg.extraArgs; KeepAlive = true; + ProcessType = "Interactive"; }; - - Install = { WantedBy = [ "sockets.target" ]; }; }; - - home.packages = [ cfg.package ]; }; - } diff --git a/modules/services/mpdscribble.nix b/modules/services/mpdscribble.nix new file mode 100644 index 000000000..d868f24b1 --- /dev/null +++ b/modules/services/mpdscribble.nix @@ -0,0 +1,222 @@ +{ config, lib, options, pkgs, ... }: + +let + cfg = config.services.mpdscribble; + mpdCfg = config.services.mpd; + mpdOpt = options.services.mpd; + + endpointUrls = { + "last.fm" = "http://post.audioscrobbler.com"; + "libre.fm" = "http://turtle.libre.fm"; + "jamendo" = "http://postaudioscrobbler.jamendo.com"; + "listenbrainz" = "http://proxy.listenbrainz.org"; + }; +in { + options.services.mpdscribble = { + + enable = lib.mkEnableOption '' + mpdscribble, an MPD client which submits info about tracks being played to + Last.fm (formerly AudioScrobbler) + ''; + + proxy = lib.mkOption { + default = null; + type = lib.types.nullOr lib.types.str; + description = '' + HTTP proxy URL. + ''; + }; + + verbose = lib.mkOption { + default = 1; + type = lib.types.int; + description = '' + Log level for the mpdscribble daemon. + ''; + }; + + journalInterval = lib.mkOption { + default = 600; + example = 60; + type = lib.types.int; + description = '' + How often should mpdscribble save the journal file? [seconds] + ''; + }; + + host = lib.mkOption { + default = (if mpdCfg.network.listenAddress != "any" then + mpdCfg.network.listenAddress + else + "localhost"); + defaultText = lib.literalExpression '' + if config.${mpdOpt.network.listenAddress} != "any" + then config.${mpdOpt.network.listenAddress} + else "localhost" + ''; + type = lib.types.str; + description = '' + Host for the mpdscribble daemon to search for a mpd daemon on. + ''; + }; + + package = lib.mkPackageOption pkgs "mpdscribble" { }; + + passwordFile = lib.mkOption { + default = null; + type = lib.types.nullOr lib.types.str; + description = '' + File containing the password for the mpd daemon. + ''; + }; + + port = lib.mkOption { + default = mpdCfg.network.port; + defaultText = lib.literalExpression "config.${mpdOpt.network.port}"; + type = lib.types.port; + description = '' + Port for the mpdscribble daemon to search for a mpd daemon on. + ''; + }; + + endpoints = lib.mkOption { + type = let + endpoint = { name, ... }: { + options = { + url = lib.mkOption { + type = lib.types.str; + default = endpointUrls.${name} or ""; + description = + "The url endpoint where the scrobble API is listening."; + }; + username = lib.mkOption { + type = lib.types.str; + description = '' + Username for the scrobble service. + ''; + }; + passwordFile = lib.mkOption { + type = lib.types.nullOr lib.types.str; + description = + "File containing the password, either as MD5SUM or cleartext."; + }; + }; + }; + in lib.types.attrsOf (lib.types.submodule endpoint); + default = { }; + example = { + "last.fm" = { + username = "foo"; + passwordFile = "/run/secrets/lastfm_password"; + }; + }; + description = '' + Endpoints to scrobble to. + If the endpoint is one of "${ + lib.concatStringsSep ''", "'' (builtins.attrNames endpointUrls) + }" the url is set automatically. + ''; + }; + + }; + + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "services.mpdscribble" pkgs + lib.platforms.linux) + ]; + systemd.user.services.mpdscribble = let + localMpd = (cfg.host == "localhost" || cfg.host == "127.0.0.1"); + + mkSection = secname: secCfg: '' + [${secname}] + url = ${secCfg.url} + username = ${secCfg.username} + password = {{${secname}_PASSWORD}} + journal = /var/lib/mpdscribble/${secname}.journal + ''; + + endpoints = + lib.concatStringsSep "\n" (lib.mapAttrsToList mkSection cfg.endpoints); + cfgTemplate = pkgs.writeText "mpdscribble.conf" '' + ## This file was automatically genenrated by home-manager and will be + ## overwritten. Do not edit. Edit your home-manager configuration instead. + + ## mpdscribble - an audioscrobbler for the Music Player Daemon. + ## http://mpd.wikia.com/wiki/Client:mpdscribble + + # HTTP proxy URL. + ${lib.optionalString (cfg.proxy != null) "proxy = ${cfg.proxy}"} + + # The location of the mpdscribble log file. The special value + # "syslog" makes mpdscribble use the local syslog daemon. On most + # systems, log messages will appear in /var/log/daemon.log then. + # "-" means log to stderr (the current terminal). + log = - + + # How verbose mpdscribble's logging should be. Default is 1. + verbose = ${toString cfg.verbose} + + # How often should mpdscribble save the journal file? [seconds] + journal_interval = ${toString cfg.journalInterval} + + # The host running MPD, possibly protected by a password + # ([PASSWORD@]HOSTNAME). + host = ${ + (lib.optionalString (cfg.passwordFile != null) "{{MPD_PASSWORD}}@") + + cfg.host + } + + # The port that the MPD listens on and mpdscribble should try to + # connect to. + port = ${toString cfg.port} + + ${endpoints} + ''; + + configFile = + "\${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/mpdscribble/mpdscribble.conf"; + + replaceSecret = secretFile: placeholder: targetFile: + lib.optionalString (secretFile != null) '' + ${pkgs.replace-secret}/bin/replace-secret '${placeholder}' '${secretFile}' "${targetFile}" + ''; + + preStart = pkgs.writeShellApplication { + name = "mpdscribble-pre-start"; + runtimeInputs = [ pkgs.replace-secret pkgs.coreutils ]; + text = '' + configFile="${configFile}" + mkdir -p "$(dirname "$configFile")" + cp --no-preserve=mode,ownership -f "${cfgTemplate}" "$configFile" + ${replaceSecret cfg.passwordFile "{{MPD_PASSWORD}}" "$configFile"} + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (secname: cfg: + replaceSecret cfg.passwordFile "{{${secname}_PASSWORD}}" + "$configFile") cfg.endpoints)} + ''; + }; + + start = pkgs.writeShellScript "mpdscribble-start" '' + configFile="${configFile}" + exec "${lib.getExe cfg.package}" --no-daemon --conf "$configFile" + ''; + + in { + Unit = { + Description = "mpdscribble mpd scrobble client"; + After = [ "network.target" ] ++ lib.optional localMpd "mpd.service"; + }; + Install.WantedBy = [ "default.target" ]; + Service = { + StateDirectory = "mpdscribble"; + RuntimeDirectory = "mpdscribble"; + RuntimeDirectoryMode = "700"; + # TODO use LoadCredential= instead of running preStart with full privileges? + ExecStartPre = "+${preStart}/bin/mpdscribble-pre-start"; + ExecStart = "${start}"; + }; + }; + }; + + meta.maintainers = [ lib.hm.maintainers.msyds ]; +} diff --git a/modules/services/network-manager-applet.nix b/modules/services/network-manager-applet.nix index 8d15aa293..8738cae66 100644 --- a/modules/services/network-manager-applet.nix +++ b/modules/services/network-manager-applet.nix @@ -28,7 +28,7 @@ in { Unit = { Description = "Network Manager applet"; Requires = [ "tray.target" ]; - After = [ "graphical-session-pre.target" "tray.target" ]; + After = [ "graphical-session.target" "tray.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/nextcloud-client.nix b/modules/services/nextcloud-client.nix index 24b3c99dd..7a3ceacb1 100644 --- a/modules/services/nextcloud-client.nix +++ b/modules/services/nextcloud-client.nix @@ -36,7 +36,7 @@ in { systemd.user.services.nextcloud-client = { Unit = { Description = "Nextcloud Client"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/notify-osd.nix b/modules/services/notify-osd.nix index 4faf83643..b118a275e 100644 --- a/modules/services/notify-osd.nix +++ b/modules/services/notify-osd.nix @@ -33,7 +33,7 @@ in { systemd.user.services.notify-osd = { Unit = { Description = "notify-osd"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/opensnitch-ui.nix b/modules/services/opensnitch-ui.nix index f45ee9cdb..a6df254f5 100644 --- a/modules/services/opensnitch-ui.nix +++ b/modules/services/opensnitch-ui.nix @@ -23,7 +23,7 @@ in { systemd.user.services.opensnitch-ui = { Unit = { Description = "Opensnitch ui"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/owncloud-client.nix b/modules/services/owncloud-client.nix index 3235dac9c..aad2d487c 100644 --- a/modules/services/owncloud-client.nix +++ b/modules/services/owncloud-client.nix @@ -24,7 +24,7 @@ in { systemd.user.services.owncloud-client = { Unit = { Description = "Owncloud Client"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/parcellite.nix b/modules/services/parcellite.nix index 39b81e869..dc6b84c41 100644 --- a/modules/services/parcellite.nix +++ b/modules/services/parcellite.nix @@ -42,7 +42,7 @@ in { Unit = { Description = "Lightweight GTK+ clipboard manager"; Requires = [ "tray.target" ]; - After = [ "graphical-session-pre.target" "tray.target" ]; + After = [ "graphical-session.target" "tray.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/pasystray.nix b/modules/services/pasystray.nix index 4ea340d21..62e203584 100644 --- a/modules/services/pasystray.nix +++ b/modules/services/pasystray.nix @@ -30,7 +30,7 @@ in { Unit = { Description = "PulseAudio system tray"; Requires = [ "tray.target" ]; - After = [ "graphical-session-pre.target" "tray.target" ]; + After = [ "graphical-session.target" "tray.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/pbgopy.nix b/modules/services/pbgopy.nix index 3a3499e52..48556a5ba 100644 --- a/modules/services/pbgopy.nix +++ b/modules/services/pbgopy.nix @@ -60,7 +60,7 @@ in { systemd.user.services.pbgopy = { Unit = { Description = "pbgopy server for sharing the clipboard between devices"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; Service = { diff --git a/modules/services/picom.nix b/modules/services/picom.nix index 1d9b7bb55..59e373a62 100644 --- a/modules/services/picom.nix +++ b/modules/services/picom.nix @@ -310,7 +310,7 @@ in { systemd.user.services.picom = { Unit = { Description = "Picom X11 compositor"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/plex-mpv-shim.nix b/modules/services/plex-mpv-shim.nix index 940e57184..795827c40 100644 --- a/modules/services/plex-mpv-shim.nix +++ b/modules/services/plex-mpv-shim.nix @@ -58,7 +58,7 @@ in { systemd.user.services.plex-mpv-shim = { Unit = { Description = "Plex mpv shim"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/podman-linux/activation.nix b/modules/services/podman-linux/activation.nix index 5791f19b0..205b6651e 100644 --- a/modules/services/podman-linux/activation.nix +++ b/modules/services/podman-linux/activation.nix @@ -18,6 +18,7 @@ local manifestFile="${config.xdg.configHome}/podman/$2" local extraListCommands="''${3:-}" [[ $resourceType = "container" ]] && extraListCommands+=" -a" + [[ $resourceType = "volume" ]] && extraListCommands+=" --filter label=nix.home-manager.preserve=false" [ ! -f "$manifestFile" ] && VERBOSE_ENABLED && echo "Manifest does not exist: $manifestFile" && return 0 @@ -27,6 +28,7 @@ formatString="{{.Name}}" [[ $resourceType = "container" ]] && formatString="{{.Names}}" + [[ $resourceType = "image" ]] && formatString="{{.Repository}}" local listOutput=$(${config.services.podman.package}/bin/podman $resourceType ls $extraListCommands --filter 'label=nix.home-manager.managed=true' --format "$formatString") @@ -36,12 +38,12 @@ VERBOSE_ENABLED && echo "No ''${resourceType}s available to process." || true else for resource in "''${podmanResources[@]}"; do - if ! isResourceInManifest "$resource"; then - removeResource "$resourceType" "$resource" - else - VERBOSE_ENABLED && echo "Keeping managed $resourceType: $resource" || true - fi - done + if ! isResourceInManifest "$resource"; then + removeResource "$resourceType" "$resource" + else + VERBOSE_ENABLED && echo "Keeping managed $resourceType: $resource" || true + fi + done fi } @@ -69,19 +71,20 @@ commands=() case "$resourceType" in "container") - commands+="${config.services.podman.package}/bin/podman $resourceType stop $resource" - commands+="${config.services.podman.package}/bin/podman $resourceType rm -f $resource" + commands+=("${config.services.podman.package}/bin/podman $resourceType stop $resource") + commands+=("${config.services.podman.package}/bin/podman $resourceType rm -f $resource") ;; - "network") - commands+="${config.services.podman.package}/bin/podman $resourceType rm $resource" + "image" | "network" | "volume") + commands+=("${config.services.podman.package}/bin/podman $resourceType rm $resource") ;; esac for command in "''${commands[@]}"; do command=$(echo $command | tr -d ';&|`') DRYRUN_ENABLED && echo "Would run: $command" && continue || true VERBOSE_ENABLED && echo "Running: $command" || true - if [[ "$(eval "$command")" != "$resource" ]]; then + if [[ "$(eval "$command")" != *"$resource" ]]; then echo -e "\tCommand failed: ''${command}" + [ "$resourceType" == "image" ] && resourceType="ancestor" usedByContainers=$(${config.services.podman.package}/bin/podman container ls -a --filter "$resourceType=$resource" --format "{{.Names}}") echo -e "\t$resource in use by containers: $usedByContainers" fi @@ -92,7 +95,7 @@ [[ "$@" == *"--verbose"* ]] && VERBOSE="true" [[ "$@" == *"--dry-run"* ]] && DRY_RUN="true" - for type in "container" "network"; do + for type in "container" "image" "network" "volume"; do cleanup "$type" "''${type}s.manifest" done ''; diff --git a/modules/services/podman-linux/builds.nix b/modules/services/podman-linux/builds.nix new file mode 100644 index 000000000..c1aed0c47 --- /dev/null +++ b/modules/services/podman-linux/builds.nix @@ -0,0 +1,173 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.services.podman; + + podman-lib = import ./podman-lib.nix { inherit pkgs lib config; }; + + createQuadletSource = name: buildDef: + let + quadlet = podman-lib.deepMerge { + Build = { + AuthFile = buildDef.authFile; + Environment = buildDef.environment; + File = buildDef.file; + ImageTag = [ "homemanager/${name}" ] ++ buildDef.tags; + Label = buildDef.labels // { "nix.home-manager.managed" = true; }; + PodmanArgs = buildDef.extraPodmanArgs; + SetWorkingDirectory = buildDef.workingDirectory; + TLSVerify = buildDef.tlsVerify; + }; + Install = { + WantedBy = optionals buildDef.autoStart [ + "default.target" + "multi-user.target" + ]; + }; + Service = { + TimeoutStartSec = 300; + RemainAfterExit = "yes"; + }; + Unit = { Description = buildDef.description; }; + } buildDef.extraConfig; + in { + attrs = quadlet; + text = '' + # Automatically generated by home-manager for podman build configuration + # DO NOT EDIT THIS FILE DIRECTLY + # + # ${name}.build + ${podman-lib.toQuadletIni quadlet} + ''; + }; + + toQuadletInternal = name: buildDef: + let src = createQuadletSource name buildDef; + in { + assertions = podman-lib.buildConfigAsserts name buildDef.extraConfig; + serviceName = + "podman-${name}"; # generated service name: 'podman--build.service + source = podman-lib.removeBlankLines src.text; + resourceType = "build"; + }; +in let + buildDefinitionType = types.submodule ({ name, ... }: { + options = { + + autoStart = mkOption { + type = types.bool; + default = true; + description = + "Whether to start the build on boot. Requires user lingering."; + }; + + authFile = mkOption { + type = with types; nullOr path; + default = null; + description = "Path of the authentication file."; + }; + + description = mkOption { + type = with types; nullOr str; + default = "Service for build ${name}"; + defaultText = "Service for build \${name}"; + example = "My Build"; + description = "The description of the build."; + }; + + environment = mkOption { + type = podman-lib.primitiveAttrs; + default = { }; + example = literalExpression '' + { + VAR1 = "0:100"; + VAR2 = true; + VAR3 = 5; + } + ''; + description = "Environment variables to set in the build."; + }; + + extraConfig = mkOption { + type = podman-lib.extraConfigType; + default = { }; + example = literalExpression '' + { + Build = { + Arch = "aarch64"; + }; + Service = { + TimeoutStartSec = 15; + }; + } + ''; + description = "INI sections and values to populate the Build Quadlet."; + }; + + extraPodmanArgs = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "--retries 5" ]; + description = "Extra arguments to pass to the podman build command."; + }; + + file = mkOption { + type = types.str; + example = literalExpression '' + `"xdg.configFile."containerfiles/my-img/Containerfile"` + or + `"https://github.com/.../my-img/Containerfile"` + ''; + description = + "Path to a Containerfile which contains instructions to build the image."; + }; + + tags = mkOption { + type = with types; listOf str; + default = [ ]; + description = '' + Name associated with the build. + First tag will always be "homemanager/". + ''; + }; + + labels = mkOption { + type = with types; attrsOf str; + default = { }; + example = { + app = "myapp"; + some-label = "somelabel"; + }; + description = "The labels to apply to the build."; + }; + + tlsVerify = mkOption { + type = types.bool; + default = true; + description = + "Require HTTPS and verification of certificates when contacting registries."; + }; + + workingDirectory = mkOption { + type = with types; nullOr path; + default = null; + description = "WorkingDirectory of the systemd unit file."; + }; + }; + }); +in { + options.services.podman.builds = mkOption { + type = types.attrsOf buildDefinitionType; + default = { }; + description = "Defines Podman build quadlet configurations."; + }; + + config = let buildQuadlets = mapAttrsToList toQuadletInternal cfg.builds; + in mkIf cfg.enable { + services.podman.internal.quadletDefinitions = buildQuadlets; + assertions = flatten (map (build: build.assertions) buildQuadlets); + + xdg.configFile."podman/images.manifest".text = + podman-lib.generateManifestText buildQuadlets; + }; +} diff --git a/modules/services/podman-linux/containers.nix b/modules/services/podman-linux/containers.nix index 41ab29130..586bcf660 100644 --- a/modules/services/podman-linux/containers.nix +++ b/modules/services/podman-linux/containers.nix @@ -5,24 +5,68 @@ with lib; let cfg = config.services.podman; - podman-lib = import ./podman-lib.nix { inherit lib config; }; + podman-lib = import ./podman-lib.nix { inherit pkgs lib config; }; createQuadletSource = name: containerDef: let - mapHmNetworks = network: - if builtins.hasAttr network cfg.networks then - "podman-${network}-network.service" - else - null; + extractQuadletReference = type: value: + let + regex = "([a-zA-Z0-9_-]+\\." + type + ").*"; + parts = builtins.match regex value; + in if parts == null then value else builtins.elemAt parts 0; - finalConfig = let - managedNetworks = if lib.isList containerDef.network then - map mapHmNetworks containerDef.network - else if containerDef.network != null then - map mapHmNetworks [ containerDef.network ] + dependencyBySuffix = type: value: + if (hasInfix ".${type}" value) then + let name = extractQuadletReference type value; + in if (hasAttr name cfg.internal.builtQuadlets) then + [ (cfg.internal.builtQuadlets.${name}) ] + else + [ ] else [ ]; - in (podman-lib.deepMerge { + + withResolverFor = type: value: + let resolve = v: dependencyBySuffix type v; + in if builtins.isList value then + builtins.concatLists (map resolve value) # Flatten list of lists + else + resolve value; + + dependencyServices = (withResolverFor "image" containerDef.image) + ++ (withResolverFor "build" containerDef.image) + ++ (withResolverFor "network" containerDef.network) + ++ (withResolverFor "volume" containerDef.volumes); + + checkQuadletReference = types: value: + if builtins.isList value then + builtins.concatLists (map (checkQuadletReference types) value) + else + let type = findFirst (t: hasInfix ".${t}" value) null types; + in if (type != null) then + let + quadletName = extractQuadletReference type value; + quadletsOfType = + filterAttrs (n: v: v.quadletData.resourceType == type) + cfg.internal.builtQuadlets; + in if (hasAttr quadletName quadletsOfType) then + [ + (replaceStrings [ quadletName ] [ "podman-${quadletName}" ] + value) + ] + else + [ value ] + else if ((hasInfix "/nix/store" value) == false + && hasAttr value cfg.internal.builtQuadlets) then + lib.warn '' + A value for Podman container '${name}' might use a reference to another quadlet: ${value}. + Append the type '.${ + cfg.internal.builtQuadlets.${value}.quadletData.resourceType + }' to '${baseName value}' if this is intended. + '' [ value ] + else + [ value ]; + + quadlet = (podman-lib.deepMerge { Container = { AddCapability = containerDef.addCapabilities; AddDevice = containerDef.devices; @@ -34,25 +78,24 @@ let EnvironmentFile = containerDef.environmentFile; Exec = containerDef.exec; Group = containerDef.group; - Image = containerDef.image; + Image = checkQuadletReference [ "build" "image" ] containerDef.image; IP = containerDef.ip4; IP6 = containerDef.ip6; Label = (containerDef.labels // { "nix.home-manager.managed" = true; }); - Network = containerDef.network; + Network = checkQuadletReference [ "network" ] containerDef.network; NetworkAlias = containerDef.networkAlias; PodmanArgs = containerDef.extraPodmanArgs; PublishPort = containerDef.ports; UserNS = containerDef.userNS; User = containerDef.user; - Volume = containerDef.volumes; + Volume = checkQuadletReference [ "volume" ] containerDef.volumes; }; Install = { - WantedBy = (if containerDef.autoStart then [ + WantedBy = optionals containerDef.autoStart [ "default.target" "multi-user.target" - ] else - [ ]); + ]; }; Service = { Environment = { @@ -60,36 +103,41 @@ let "/run/wrappers/bin" "/run/current-system/sw/bin" "${config.home.homeDirectory}/.nix-profile/bin" + "${pkgs.systemd}/bin" ]); }; Restart = "always"; TimeoutStopSec = 30; }; Unit = { - After = [ "network.target" ] ++ managedNetworks; - Requires = managedNetworks; Description = (if (builtins.isString containerDef.description) then containerDef.description else "Service for container ${name}"); }; } containerDef.extraConfig); - in '' - # Automatically generated by home-manager podman container configuration - # DO NOT EDIT THIS FILE DIRECTLY - # - # ${name}.container - ${podman-lib.toQuadletIni finalConfig} - ''; + in { + dependencies = dependencyServices; + attrs = quadlet; + text = '' + # Automatically generated by home-manager podman container configuration + # DO NOT EDIT THIS FILE DIRECTLY + # + # ${name}.container + ${podman-lib.toQuadletIni quadlet} + ''; + }; - toQuadletInternal = name: containerDef: { - assertions = podman-lib.buildConfigAsserts name containerDef.extraConfig; - resourceType = "container"; - serviceName = - "podman-${name}"; # quadlet service name: 'podman-.service' - source = - podman-lib.removeBlankLines (createQuadletSource name containerDef); - }; + toQuadletInternal = name: containerDef: + let src = createQuadletSource name containerDef; + in { + assertions = podman-lib.buildConfigAsserts name containerDef.extraConfig; + dependencies = src.dependencies; + resourceType = "container"; + serviceName = + "podman-${src.attrs.Container.ContainerName}"; # generated service name: 'podman-.service' + source = podman-lib.removeBlankLines src.text; + }; # Define the container user type as the user interface containerDefinitionType = types.submodule { @@ -307,7 +355,7 @@ in { flatten (map (container: container.assertions) containerQuadlets); # manifest file - home.file."${config.xdg.configHome}/podman/containers.manifest".text = + xdg.configFile."podman/containers.manifest".text = podman-lib.generateManifestText containerQuadlets; }; } diff --git a/modules/services/podman-linux/default.nix b/modules/services/podman-linux/default.nix index 459762d46..a08541a6d 100644 --- a/modules/services/podman-linux/default.nix +++ b/modules/services/podman-linux/default.nix @@ -5,8 +5,15 @@ let in { meta.maintainers = with lib.hm.maintainers; [ bamhm182 n-hass ]; - imports = - [ ./containers.nix ./install-quadlet.nix ./networks.nix ./services.nix ]; + imports = [ + ./builds.nix + ./containers.nix + ./images.nix + ./install-quadlet.nix + ./networks.nix + ./services.nix + ./volumes.nix + ]; options.services.podman = { enable = lib.mkEnableOption "Podman, a daemonless container engine"; diff --git a/modules/services/podman-linux/images.nix b/modules/services/podman-linux/images.nix new file mode 100644 index 000000000..58bb97da1 --- /dev/null +++ b/modules/services/podman-linux/images.nix @@ -0,0 +1,162 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.services.podman; + + podman-lib = import ./podman-lib.nix { inherit pkgs lib config; }; + + createQuadletSource = name: imageDef: + let + credsString = + (if imageDef.username != null then imageDef.username else "") + + (if imageDef.password != null then ":${imageDef.password}" else ""); + + quadlet = podman-lib.deepMerge { + Image = { + AuthFile = imageDef.authFile; + CertDir = imageDef.certDir; + Creds = (if credsString != "" then credsString else null); + DecryptionKey = imageDef.decryptionKeyFile; + Image = imageDef.image; + ImageTag = imageDef.tag; + PodmanArgs = imageDef.extraPodmanArgs; + TLSVerify = imageDef.tlsVerify; + }; + Install = { + WantedBy = optionals imageDef.autoStart [ + "default.target" + "multi-user.target" + ]; + }; + Service = { + ExecStartPre = [ "${podman-lib.awaitPodmanUnshare}" ]; + TimeoutStartSec = 300; + RemainAfterExit = "yes"; + }; + Unit = { Description = imageDef.description; }; + } imageDef.extraConfig; + in '' + # Automatically generated by home-manager for podman image configuration + # DO NOT EDIT THIS FILE DIRECTLY + # + # ${name}.image + ${podman-lib.toQuadletIni quadlet} + ''; + + toQuadletInternal = name: imageDef: { + assertions = podman-lib.buildConfigAsserts name imageDef.extraConfig; + serviceName = + "podman-${name}"; # generated service name: 'podman--image.service + source = podman-lib.removeBlankLines (createQuadletSource name imageDef); + resourceType = "image"; + }; +in let + imageDefinitionType = types.submodule ({ name, ... }: { + options = { + autoStart = mkOption { + type = types.bool; + default = true; + description = + "Whether to pull the image on boot. Requires user lingering."; + }; + + authFile = mkOption { + type = with types; nullOr path; + default = null; + description = + "Path of the authentication file used to connect to registry."; + }; + + certDir = mkOption { + type = with types; nullOr path; + default = null; + description = + "Path of certificates (*.{crt,cert,key}) used to connect to registry."; + }; + + decryptionKeyFile = mkOption { + type = with types; nullOr path; + default = null; + description = "Path to key used for decryption of images."; + }; + + description = mkOption { + type = with types; nullOr str; + default = "Service for image ${name}"; + defaultText = "Service for image \${name}"; + example = "My Image"; + description = "The description of the image."; + }; + + extraConfig = mkOption { + type = podman-lib.extraConfigType; + default = { }; + example = literalExpression '' + { + Image = { + ContainersConfModule = "/etc/nvd.conf"; + }; + } + ''; + description = "INI sections and values to populate the Image Quadlet."; + }; + + extraPodmanArgs = mkOption { + type = with types; listOf str; + default = [ ]; + example = [ "--os=linux" ]; + description = + "Extra arguments to pass to the podman image pull command."; + }; + + image = mkOption { + type = types.str; + example = "quay.io/centos/centos:latest"; + description = "Image to pull."; + }; + + password = mkOption { + type = with types; nullOr str; + default = null; + example = "P@ssw0rd"; + description = + "Password used to connect to registry. (Will be visible in nix store)"; + }; + + tag = mkOption { + type = with types; nullOr str; + default = null; + example = "quay.io/centos/centos:latest"; + description = + "FQIN of referenced Image when source is a file or directory archive."; + }; + + tlsVerify = mkOption { + type = types.bool; + default = true; + description = + "Require HTTPS and verification of certificates when contacting registries."; + }; + + username = mkOption { + type = with types; nullOr str; + default = null; + example = "bob"; + description = "Username used to connect to registry."; + }; + + }; + }); +in { + options.services.podman.images = mkOption { + type = types.attrsOf imageDefinitionType; + default = { }; + description = "Defines Podman image quadlet configurations."; + }; + + config = let imageQuadlets = mapAttrsToList toQuadletInternal cfg.images; + in mkIf cfg.enable { + services.podman.internal.quadletDefinitions = imageQuadlets; + assertions = flatten (map (image: image.assertions) imageQuadlets); + }; +} diff --git a/modules/services/podman-linux/install-quadlet.nix b/modules/services/podman-linux/install-quadlet.nix index 8ce6a33e8..a079b0be0 100644 --- a/modules/services/podman-linux/install-quadlet.nix +++ b/modules/services/podman-linux/install-quadlet.nix @@ -5,7 +5,7 @@ with lib; let cfg = config.services.podman; - podman-lib = import ./podman-lib.nix { inherit lib config; }; + podman-lib = import ./podman-lib.nix { inherit pkgs lib config; }; activation = import ./activation.nix { inherit config podman-lib; }; activationCleanupScript = activation.cleanup; @@ -15,14 +15,16 @@ let pkgs.stdenv.mkDerivation { name = "home-${quadlet.resourceType}-${quadlet.serviceName}"; - buildInputs = [ cfg.package ]; + buildInputs = [ cfg.package ] ++ quadlet.dependencies; - dontUnpack = true; + unpackPhase = '' + mkdir -p $out/quadlets + ${concatStringsSep "\n" (map (v: + "echo 'linking ${v.quadletData.serviceName}.${v.quadletData.resourceType}'; ln -s ${v.out}/quadlets/${v.quadletData.serviceName}.${v.quadletData.resourceType} $out/quadlets") + quadlet.dependencies)} + ''; installPhase = '' - mkdir $out - # Directory for the quadlet file - mkdir -p $out/quadlets # Directory for systemd unit files mkdir -p $out/units @@ -40,7 +42,6 @@ let }; }; - # Create a derivation for each quadlet spec builtQuadlets = map buildPodmanQuadlet cfg.internal.quadletDefinitions; accumulateUnitFiles = prefix: path: quadlet: @@ -84,5 +85,11 @@ in { home.activation.podmanQuadletCleanup = lib.mkIf (lib.length builtQuadlets >= 1) (lib.hm.dag.entryAfter [ "reloadSystemd" ] activationCleanupScript); + + services.podman.internal.builtQuadlets = listToAttrs (map (pkg: { + name = (removePrefix "podman-" pkg.passthru.quadletData.serviceName) + "." + + pkg.passthru.quadletData.resourceType; + value = pkg; + }) builtQuadlets); }; } diff --git a/modules/services/podman-linux/networks.nix b/modules/services/podman-linux/networks.nix index bb4ac5915..2ab9f2031 100644 --- a/modules/services/podman-linux/networks.nix +++ b/modules/services/podman-linux/networks.nix @@ -5,17 +5,11 @@ with lib; let cfg = config.services.podman; - podman-lib = import ./podman-lib.nix { inherit lib config; }; - - awaitPodmanUnshare = pkgs.writeShellScript "await-podman-unshare" '' - until ${cfg.package}/bin/podman unshare ${pkgs.coreutils}/bin/true; do - sleep 1; - done - ''; + podman-lib = import ./podman-lib.nix { inherit pkgs lib config; }; createQuadletSource = name: networkDef: let - cfg = (podman-lib.deepMerge { + quadlet = (podman-lib.deepMerge { Install = { WantedBy = (if networkDef.autoStart then [ "default.target" @@ -39,7 +33,7 @@ let "${makeBinPath [ pkgs.su pkgs.coreutils ]}" ]); }; - ExecStartPre = [ "${awaitPodmanUnshare}" ]; + ExecStartPre = [ "${podman-lib.awaitPodmanUnshare}" ]; TimeoutStartSec = 15; RemainAfterExit = "yes"; }; @@ -56,13 +50,13 @@ let # DO NOT EDIT THIS FILE DIRECTLY # # ${name}.network - ${podman-lib.toQuadletIni cfg} + ${podman-lib.toQuadletIni quadlet} ''; toQuadletInternal = name: networkDef: { assertions = podman-lib.buildConfigAsserts name networkDef.extraConfig; serviceName = - "podman-${name}"; # quadlet service name: 'podman--network.service' + "podman-${name}"; # generated service name: 'podman--network.service' source = podman-lib.removeBlankLines (createQuadletSource name networkDef); resourceType = "network"; }; @@ -162,7 +156,7 @@ in { services.podman.internal.quadletDefinitions = networkQuadlets; assertions = flatten (map (network: network.assertions) networkQuadlets); - home.file."${config.xdg.configHome}/podman/networks.manifest".text = + xdg.configFile."podman/networks.manifest".text = podman-lib.generateManifestText networkQuadlets; }; } diff --git a/modules/services/podman-linux/options.nix b/modules/services/podman-linux/options.nix index 242028aea..850660c00 100644 --- a/modules/services/podman-linux/options.nix +++ b/modules/services/podman-linux/options.nix @@ -11,6 +11,13 @@ let description = "List of Nix type assertions."; }; + dependencies = lib.mkOption { + type = with lib.types; listOf package; + default = [ ]; + internal = true; + description = "List of systemd service dependencies."; + }; + resourceType = lib.mkOption { type = lib.types.str; default = ""; @@ -33,11 +40,19 @@ let }; in { options.services.podman = { - internal.quadletDefinitions = lib.mkOption { - type = lib.types.listOf quadletInternalType; - default = { }; - internal = true; - description = "List of quadlet source file content and service names."; + internal = { + quadletDefinitions = lib.mkOption { + type = lib.types.listOf quadletInternalType; + default = { }; + internal = true; + description = "List of quadlet source file content and service names."; + }; + builtQuadlets = lib.mkOption { + type = with lib.types; attrsOf package; + default = { }; + internal = true; + description = "All built quadlets."; + }; }; package = lib.mkOption { diff --git a/modules/services/podman-linux/podman-lib.nix b/modules/services/podman-linux/podman-lib.nix index 1acc930fc..30ffcc836 100644 --- a/modules/services/podman-linux/podman-lib.nix +++ b/modules/services/podman-linux/podman-lib.nix @@ -1,4 +1,4 @@ -{ lib, config, ... }: +{ pkgs, lib, config, ... }: with lib; @@ -63,8 +63,10 @@ in { buildConfigAsserts = quadletName: extraConfig: let configRules = { + Build = { ImageTag = (with types; listOf str); }; Container = { ContainerName = types.enum [ quadletName ]; }; Network = { NetworkName = types.enum [ quadletName ]; }; + Volume = { VolumeName = types.enum [ quadletName ]; }; }; # Function to build assertions for a specific section and its attributes. @@ -83,8 +85,23 @@ in { else [ ]; + checkImageTag = extraConfig: + let + imageTags = (extraConfig.Build or { }).ImageTag or [ ]; + containsRequiredTag = + builtins.elem "homemanager/${quadletName}" imageTags; + imageTagsStr = concatMapStringsSep ''" "'' toString imageTags; + in [{ + assertion = imageTags == [ ] || containsRequiredTag; + message = '' + In '${quadletName}' config. Build.ImageTag: '[ "${imageTagsStr}" ]' does not contain 'homemanager/${quadletName}'.''; + }]; + # Flatten assertions from all sections in `extraConfig`. - in flatten (mapAttrsToList buildSectionAsserts extraConfig); + in flatten (concatLists [ + (mapAttrsToList buildSectionAsserts extraConfig) + (checkImageTag extraConfig) + ]); extraConfigType = with types; attrsOf (attrsOf (oneOf [ primitiveAttrs primitiveList primitive ])); @@ -107,8 +124,10 @@ in { # specific logic for writing the unit name goes here. It should be # identical to what `podman ls` shows in { + "build" = "localhost/homemanager/${strippedName}"; "container" = strippedName; "network" = strippedName; + "volume" = strippedName; }."${quadlet.resourceType}"; in if allQuadletsSameType then '' ${concatStringsSep "\n" @@ -133,4 +152,10 @@ in { lines = splitString "\n" text; nonEmptyLines = filter (line: line != "") lines; in concatStringsSep "\n" nonEmptyLines; + + awaitPodmanUnshare = pkgs.writeShellScript "await-podman-unshare" '' + until ${config.services.podman.package}/bin/podman unshare ${pkgs.coreutils}/bin/true; do + ${pkgs.coreutils}/bin/sleep 1 + done + ''; } diff --git a/modules/services/podman-linux/services.nix b/modules/services/podman-linux/services.nix index 87ff83ad8..4a22b703f 100644 --- a/modules/services/podman-linux/services.nix +++ b/modules/services/podman-linux/services.nix @@ -42,8 +42,8 @@ in { "${config.home.homeDirectory}/.nix-profile/bin" ] }"; - ExecStart = "${pkgs.podman}/bin/podman auto-update"; - ExecStartPost = "${pkgs.podman}/bin/podman image prune -f"; + ExecStart = "${cfg.package}/bin/podman auto-update"; + ExecStartPost = "${cfg.package}/bin/podman image prune -f"; TimeoutStartSec = "300s"; TimeoutStopSec = "10s"; }; @@ -65,7 +65,9 @@ in { xdg.configFile."systemd/user/podman-user-wait-network-online.service.d/50-exec-search-path.conf".text = '' [Service] - ExecSearchPath=${pkgs.bashInteractive}/bin:${pkgs.systemd}/bin:/bin + ExecSearchPath=${ + makeBinPath (with pkgs; [ bashInteractive systemd coreutils ]) + }:/bin ''; }) ]); diff --git a/modules/services/podman-linux/volumes.nix b/modules/services/podman-linux/volumes.nix new file mode 100644 index 000000000..93c8dcd4a --- /dev/null +++ b/modules/services/podman-linux/volumes.nix @@ -0,0 +1,186 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.podman; + + podman-lib = import ./podman-lib.nix { inherit pkgs lib config; }; + + createQuadletSource = name: volumeDef: + let + quadlet = podman-lib.deepMerge { + Install = { + WantedBy = optionals volumeDef.autoStart [ + "default.target" + "multi-user.target" + ]; + }; + Service = { + Environment = { + PATH = (builtins.concatStringsSep ":" [ + "${podman-lib.newuidmapPaths}" + "${makeBinPath [ pkgs.su pkgs.coreutils ]}" + ]); + }; + ExecStartPre = [ "${podman-lib.awaitPodmanUnshare}" ]; + TimeoutStartSec = 15; + RemainAfterExit = "yes"; + }; + Unit = { Description = volumeDef.description; }; + Volume = { + Copy = volumeDef.copy; + Device = volumeDef.device; + Driver = volumeDef.driver; + Group = volumeDef.group; + Image = volumeDef.image; + Label = volumeDef.labels // { + "nix.home-manager.managed" = true; + "nix.home-manager.preserve" = volumeDef.preserve; + }; + PodmanArgs = volumeDef.extraPodmanArgs; + Type = volumeDef.type; + User = volumeDef.user; + VolumeName = name; + }; + } volumeDef.extraConfig; + in '' + # Automatically generated by home-manager for podman volume configuration + # DO NOT EDIT THIS FILE DIRECTLY + # + # ${name}.volume + ${podman-lib.toQuadletIni quadlet} + ''; + + toQuadletInternal = name: volumeDef: { + assertions = podman-lib.buildConfigAsserts name volumeDef.extraConfig; + serviceName = + "podman-${name}"; # generated service name: 'podman--volume.service' + source = podman-lib.removeBlankLines (createQuadletSource name volumeDef); + resourceType = "volume"; + }; + +in let + volumeDefinitionType = types.submodule ({ name, ... }: { + options = { + + autoStart = mkOption { + type = types.bool; + default = true; + description = "Whether to create the volume on boot."; + }; + + copy = mkOption { + type = types.bool; + default = true; + description = + "Copy content of the image located at the mountpoint of the volume on first run."; + }; + + description = mkOption { + type = with types; nullOr str; + default = "Service for volume ${name}"; + defaultText = "Service for volume \${name}"; + example = "My Volume"; + description = "The description of the volume."; + }; + + device = mkOption { + type = with types; nullOr str; + default = null; + example = "tmpfs"; + description = "The path of a device which is mounted for the volume."; + }; + + driver = mkOption { + type = with types; nullOr str; + default = null; + example = "image"; + description = "The volume driver to use."; + }; + + extraConfig = mkOption { + type = podman-lib.extraConfigType; + default = { }; + example = literalExpression '' + { + Volume = { + ContainerConfModule = "/etc/nvd.conf"; + }; + } + ''; + description = "INI sections and values to populate the Volume Quadlet."; + }; + + extraPodmanArgs = mkOption { + type = with types; listOf str; + default = [ ]; + example = [ "--opt copy" ]; + description = + "Extra arguments to pass to the podman volume create command."; + }; + + group = mkOption { + type = with types; nullOr (either int str); + default = null; + description = "The group ID owning the volume inside the container."; + }; + + image = mkOption { + type = with types; nullOr str; + default = null; + example = "quay.io/centos/centos:latest"; + description = + "Specifies the image the volume is based on when Driver is set to the image."; + }; + + labels = mkOption { + type = with types; attrsOf str; + default = { }; + example = { + app = "myapp"; + some-label = "somelabel"; + }; + description = "The labels to apply to the volume."; + }; + + preserve = mkOption { + type = types.bool; + default = true; + description = '' + Whether the volume should be preserved if it is removed from the configuration. + Setting this to false will cause the volume to be deleted if the volume is removed from the configuration + ''; + }; + + type = mkOption { + type = with types; nullOr str; + default = null; + example = "tmpfs"; + description = + "Filesystem type of Device. (used as -t in mount commands)"; + }; + + user = mkOption { + type = with types; nullOr (either int str); + default = null; + description = "The user ID owning the volume inside the container."; + }; + }; + }); +in { + options.services.podman.volumes = mkOption { + type = types.attrsOf volumeDefinitionType; + default = { }; + description = "Defines Podman volume quadlet configurations."; + }; + + config = let volumeQuadlets = mapAttrsToList toQuadletInternal cfg.volumes; + in mkIf cfg.enable { + services.podman.internal.quadletDefinitions = volumeQuadlets; + assertions = flatten (map (volume: volume.assertions) volumeQuadlets); + + xdg.configFile."podman/volumes.manifest".text = + podman-lib.generateManifestText volumeQuadlets; + }; +} diff --git a/modules/services/polkit-gnome.nix b/modules/services/polkit-gnome.nix new file mode 100644 index 000000000..c65ce1a0b --- /dev/null +++ b/modules/services/polkit-gnome.nix @@ -0,0 +1,32 @@ +{ config, lib, pkgs, ... }: +let + inherit (lib) + mkEnableOption mkPackageOption types literalExpression mkIf maintainers; + cfg = config.services.polkit-gnome; +in { + meta.maintainers = [ maintainers.bobvanderlinden ]; + + options = { + services.polkit-gnome = { + enable = mkEnableOption "GNOME Policykit Agent"; + package = mkPackageOption pkgs "polkit_gnome" { }; + }; + }; + + config = mkIf cfg.enable { + systemd.user.services.polkit-gnome = { + Unit = { + Description = "GNOME PolicyKit Agent"; + After = [ "graphical-session-pre.target" ]; + PartOf = [ "graphical-session.target" ]; + }; + + Install = { WantedBy = [ "graphical-session.target" ]; }; + + Service = { + ExecStart = + "${cfg.package}/libexec/polkit-gnome-authentication-agent-1"; + }; + }; + }; +} diff --git a/modules/services/poweralertd.nix b/modules/services/poweralertd.nix index 9c59ad3f0..20481e905 100644 --- a/modules/services/poweralertd.nix +++ b/modules/services/poweralertd.nix @@ -44,7 +44,7 @@ in { Unit = { Description = "UPower-powered power alerter"; Documentation = "man:poweralertd(1)"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/psd.nix b/modules/services/psd.nix index 477176aa3..eed04f3fa 100644 --- a/modules/services/psd.nix +++ b/modules/services/psd.nix @@ -4,6 +4,14 @@ let cfg = config.services.psd; + configFile = '' + ${lib.optionalString (cfg.browsers != [ ]) '' + BROWSERS=(${lib.concatStringsSep " " cfg.browsers}) + ''} + + USE_BACKUP="${if cfg.useBackup then "yes" else "no"}" + BACKUP_LIMIT=${builtins.toString cfg.backupLimit} + ''; in { meta.maintainers = [ lib.hm.maintainers.danjujan ]; @@ -22,6 +30,34 @@ in { defaults to seconds if omitted. ''; }; + + browsers = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + example = [ "chromium" "google-chrome" "firefox" ]; + description = '' + A list of browsers to sync. An empty list will enable all browsers to be managed by profile-sync-daemon. + + Available choices are: + chromium chromium-dev conkeror.mozdev.org epiphany falkon firefox firefox-trunk google-chrome google-chrome-beta google-chrome-unstable heftig-aurora icecat inox luakit midori opera opera-beta opera-developer opera-legacy otter-browser qupzilla qutebrowser palemoon rekonq seamonkey surf vivaldi vivaldi-snapshot + ''; + }; + + useBackup = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to completly enable or disable the crash recovery feature. + ''; + }; + + backupLimit = lib.mkOption { + type = lib.types.ints.unsigned; + default = 5; + description = '' + Maximum number of crash recovery snapshots to keep (the oldest ones are deleted first). + ''; + }; }; config = lib.mkIf cfg.enable { @@ -38,6 +74,10 @@ in { rsync kmod gawk + gnugrep + gnused + coreutils + findutils nettools util-linux profile-sync-daemon @@ -84,5 +124,7 @@ in { Timer = { OnUnitActiveSec = cfg.resyncTimer; }; }; }; + + xdg.configFile."psd/psd.conf".text = configFile; }; } diff --git a/modules/services/pueue.nix b/modules/services/pueue.nix index f0603bb47..1e35f0614 100644 --- a/modules/services/pueue.nix +++ b/modules/services/pueue.nix @@ -15,7 +15,7 @@ in { options.services.pueue = { enable = mkEnableOption "Pueue, CLI process scheduler and manager"; - package = mkPackageOption pkgs "pueue" { }; + package = mkPackageOption pkgs "pueue" { nullable = true; }; settings = mkOption { type = yamlFormat.type; @@ -38,11 +38,11 @@ in { assertions = [ (hm.assertions.assertPlatform "services.pueue" pkgs platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xdg.configFile."pueue/pueue.yml".source = configFile; - systemd.user = { + systemd.user = lib.mkIf (cfg.package != null) { services.pueued = { Unit = { Description = "Pueue Daemon - CLI process scheduler and manager"; diff --git a/modules/services/pulseeffects.nix b/modules/services/pulseeffects.nix index 3edc53499..c4a150c17 100644 --- a/modules/services/pulseeffects.nix +++ b/modules/services/pulseeffects.nix @@ -52,7 +52,7 @@ in { Unit = { Description = "Pulseeffects daemon"; Requires = [ "dbus.service" ]; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" "pulseaudio.service" ]; }; diff --git a/modules/services/random-background.nix b/modules/services/random-background.nix index 7e887f32e..499dc4e3b 100644 --- a/modules/services/random-background.nix +++ b/modules/services/random-background.nix @@ -76,7 +76,7 @@ in { systemd.user.services.random-background = { Unit = { Description = "Set random desktop background using feh"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/redshift-gammastep/lib/options.nix b/modules/services/redshift-gammastep/lib/options.nix index 81347e643..476f8baa3 100644 --- a/modules/services/redshift-gammastep/lib/options.nix +++ b/modules/services/redshift-gammastep/lib/options.nix @@ -189,7 +189,7 @@ in { in { Description = "${programName} colour temperature adjuster"; Documentation = serviceDocumentation; - After = [ "graphical-session-pre.target" ] ++ geoclueAgentService; + After = [ "graphical-session.target" ] ++ geoclueAgentService; Wants = geoclueAgentService; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/remmina.nix b/modules/services/remmina.nix index dac0471db..de86fe215 100644 --- a/modules/services/remmina.nix +++ b/modules/services/remmina.nix @@ -39,7 +39,7 @@ in { Unit = { Description = "Remmina remote desktop client"; Documentation = "man:remmina(1)"; - Requires = [ "graphical-session-pre.target" ]; + Requires = [ "graphical-session.target" ]; }; Service = { diff --git a/modules/services/rsibreak.nix b/modules/services/rsibreak.nix index d587c2daf..e3743090f 100644 --- a/modules/services/rsibreak.nix +++ b/modules/services/rsibreak.nix @@ -23,7 +23,7 @@ in { systemd.user.services.rsibreak = { Unit = { Description = "RSI break timer"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/screen-locker.nix b/modules/services/screen-locker.nix index 085573f8a..3e2b14b11 100644 --- a/modules/services/screen-locker.nix +++ b/modules/services/screen-locker.nix @@ -31,6 +31,14 @@ in { example = "\${pkgs.i3lock}/bin/i3lock -n -c 000000"; }; + lockCmdEnv = lib.mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "XSECURELOCK_PAM_SERVICE=xsecurelock" ]; + description = + "Environment variables to source a with the locker command (lockCmd)."; + }; + inactiveInterval = mkOption { type = types.int; default = 10; @@ -117,7 +125,7 @@ in { systemd.user.services.xss-lock = { Unit = { Description = "xss-lock, session locker service"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; @@ -127,6 +135,8 @@ in { ExecStart = concatStringsSep " " ([ "${cfg.xss-lock.package}/bin/xss-lock" "-s \${XDG_SESSION_ID}" ] ++ cfg.xss-lock.extraOptions ++ [ "-- ${cfg.lockCmd}" ]); + Environment = cfg.lockCmdEnv; + Restart = "always"; }; }; } @@ -140,7 +150,7 @@ in { systemd.user.services.xautolock-session = { Unit = { Description = "xautolock, session locker service"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; @@ -153,6 +163,7 @@ in { "-locker '${pkgs.systemd}/bin/loginctl lock-session \${XDG_SESSION_ID}'" ] ++ optional cfg.xautolock.detectSleep "-detectsleep" ++ cfg.xautolock.extraOptions); + Restart = "always"; }; }; }) diff --git a/modules/services/sctd.nix b/modules/services/sctd.nix index 44c770264..4e9671747 100644 --- a/modules/services/sctd.nix +++ b/modules/services/sctd.nix @@ -30,7 +30,7 @@ with lib; Unit = { Description = "Dynamically adjust the screen color temperature twice every minute"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/skhd.nix b/modules/services/skhd.nix new file mode 100644 index 000000000..e93f17db0 --- /dev/null +++ b/modules/services/skhd.nix @@ -0,0 +1,83 @@ +{ config, lib, pkgs, ... }: +let cfg = config.services.skhd; +in { + meta.maintainers = [ lib.maintainers.khaneliman ]; + + options.services.skhd = { + enable = lib.mkEnableOption "skhd"; + + package = lib.mkPackageOption pkgs "skhd" { }; + + errorLogFile = lib.mkOption { + type = with lib.types; nullOr (either path str); + defaultText = lib.literalExpression + "\${config.home.homeDirectory}/Library/Logs/skhd/err.log"; + example = "/Users/khaneliman/Library/Logs/skhd.log"; + description = "Absolute path to log all stderr output."; + }; + + outLogFile = lib.mkOption { + type = with lib.types; nullOr (either path str); + defaultText = lib.literalExpression + "\${config.home.homeDirectory}/Library/Logs/skhd/out.log"; + example = "/Users/khaneliman/Library/Logs/skhd.log"; + description = "Absolute path to log all stdout output."; + }; + + config = lib.mkOption { + type = with lib.types; nullOr (either path lines); + default = null; + example = '' + # open terminal, blazingly fast compared to iTerm/Hyper + cmd - return : /Applications/kitty.app/Contents/MacOS/kitty --single-instance -d ~ + + # open qutebrowser + cmd + shift - return : ~/Scripts/qtb.sh + + # open mpv + cmd - m : open -na /Applications/mpv.app $(pbpaste) + ''; + description = '' + Contents of skhd's configuration file. If empty (the default), the configuration file won't be managed. + + See [documentation](https://github.com/koekeishiya/skhd) + and [example](https://github.com/koekeishiya/skhd/blob/master/examples/skhdrc). + ''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "services.skhd" pkgs + lib.platforms.darwin) + ]; + + home.packages = [ cfg.package ]; + + launchd.agents.skhd = { + enable = true; + config = { + ProgramArguments = [ (lib.getExe cfg.package) ]; + ProcessType = "Interactive"; + KeepAlive = true; + RunAtLoad = true; + StandardErrorPath = cfg.errorLogFile; + StandardOutPath = cfg.outLogFile; + }; + }; + + services.skhd = { + errorLogFile = lib.mkOptionDefault + "${config.home.homeDirectory}/Library/Logs/skhd/skhd.err.log"; + outLogFile = lib.mkOptionDefault + "${config.home.homeDirectory}/Library/Logs/skhd/skhd.out.log"; + }; + + xdg.configFile."skhd/skhdrc" = lib.mkIf (cfg.config != null) { + source = if builtins.isPath cfg.config || lib.isStorePath cfg.config then + cfg.config + else + pkgs.writeScript "skhdrc" cfg.config; + }; + }; +} diff --git a/modules/services/swaync.nix b/modules/services/swaync.nix index c637a3338..fddf074f8 100644 --- a/modules/services/swaync.nix +++ b/modules/services/swaync.nix @@ -79,7 +79,8 @@ in { config = lib.mkIf cfg.enable { # at-spi2-core is to minimize journalctl noise of: # "AT-SPI: Error retrieving accessibility bus address: org.freedesktop.DBus.Error.ServiceUnknown: The name org.a11y.Bus was not provided by any .service files" - home.packages = [ cfg.package pkgs.at-spi2-core ]; + home.packages = + lib.mkIf (cfg.package != null) [ cfg.package pkgs.at-spi2-core ]; xdg.configFile = { "swaync/config.json".source = @@ -92,7 +93,7 @@ in { }; }; - systemd.user.services.swaync = { + systemd.user.services.swaync = lib.mkIf (cfg.package != null) { Unit = { Description = "Swaync notification daemon"; Documentation = "https://github.com/ErikReider/SwayNotificationCenter"; diff --git a/modules/services/swww.nix b/modules/services/swww.nix new file mode 100644 index 000000000..ae952d390 --- /dev/null +++ b/modules/services/swww.nix @@ -0,0 +1,37 @@ +{ config, lib, pkgs, ... }: +let cfg = config.services.swww; +in { + meta.maintainers = with lib.hm.maintainers; [ hey2022 ]; + + options.services.swww = { + enable = + lib.mkEnableOption "swww, a Solution to your Wayland Wallpaper Woes"; + package = lib.mkPackageOption pkgs "swww" { }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "services.swww" pkgs + lib.platforms.linux) + ]; + + home.packages = [ cfg.package ]; + + systemd.user.services.swww = { + Install = { WantedBy = [ config.wayland.systemd.target ]; }; + + Unit = { + ConditionEnvironment = "WAYLAND_DISPLAY"; + Description = "swww-daemon"; + After = [ config.wayland.systemd.target ]; + PartOf = [ config.wayland.systemd.target ]; + }; + + Service = { + ExecStart = "${lib.getExe' cfg.package "swww-daemon"}"; + Restart = "always"; + RestartSec = 10; + }; + }; + }; +} diff --git a/modules/services/syncthing.nix b/modules/services/syncthing.nix index 72c578ba1..02d6c96c7 100644 --- a/modules/services/syncthing.nix +++ b/modules/services/syncthing.nix @@ -608,8 +608,8 @@ in { command = mkOption { type = str; - default = "syncthingtray"; - defaultText = literalExpression "syncthingtray"; + default = "syncthingtray --wait"; + defaultText = literalExpression "syncthingtray --wait"; example = literalExpression "qsyncthingtray"; description = "Syncthing tray command to use."; }; @@ -706,7 +706,7 @@ in { }; syncthing-init = { - enable = true; + enable = cleanedConfig != { }; config = { ProgramArguments = [ "${updateConfig}" ]; WatchPaths = [ @@ -728,7 +728,7 @@ in { Unit = { Description = cfg.tray.package.pname; Requires = [ "tray.target" ]; - After = [ "graphical-session-pre.target" "tray.target" ]; + After = [ "graphical-session.target" "tray.target" ]; PartOf = [ "graphical-session.target" ]; }; @@ -753,7 +753,7 @@ in { Unit = { Description = "syncthingtray"; Requires = [ "tray.target" ]; - After = [ "graphical-session-pre.target" "tray.target" ]; + After = [ "graphical-session.target" "tray.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/trayscale.nix b/modules/services/trayscale.nix index d9853d7aa..0760448c6 100644 --- a/modules/services/trayscale.nix +++ b/modules/services/trayscale.nix @@ -28,7 +28,7 @@ in { Description = "An unofficial GUI wrapper around the Tailscale CLI client"; Requires = [ "tray.target" ]; - After = [ "graphical-session-pre.target" "tray.target" ]; + After = [ "graphical-session.target" "tray.target" ]; PartOf = [ "graphical-session.target" ]; }; Install = { WantedBy = [ "graphical-session.target" ]; }; diff --git a/modules/services/twmn.nix b/modules/services/twmn.nix index c29ff621b..e4d9f67b9 100644 --- a/modules/services/twmn.nix +++ b/modules/services/twmn.nix @@ -361,7 +361,7 @@ in { systemd.user.services.twmnd = { Unit = { Description = "twmn daemon"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; X-Restart-Triggers = [ "${config.xdg.configFile."twmn/twmn.conf".source}" ]; diff --git a/modules/services/udiskie.nix b/modules/services/udiskie.nix index 2572b3594..c6165ecf5 100644 --- a/modules/services/udiskie.nix +++ b/modules/services/udiskie.nix @@ -116,7 +116,7 @@ in { Unit = { Description = "udiskie mount daemon"; Requires = lib.optional (cfg.tray != "never") "tray.target"; - After = [ "graphical-session-pre.target" ] + After = [ "graphical-session.target" ] ++ lib.optional (cfg.tray != "never") "tray.target"; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/unclutter.nix b/modules/services/unclutter.nix index e08c23eb3..d0327b5e1 100644 --- a/modules/services/unclutter.nix +++ b/modules/services/unclutter.nix @@ -45,7 +45,7 @@ in { systemd.user.services.unclutter = { Unit = { Description = "unclutter"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/window-managers/fluxbox.nix b/modules/services/window-managers/fluxbox.nix index c06b14d60..f84714742 100644 --- a/modules/services/window-managers/fluxbox.nix +++ b/modules/services/window-managers/fluxbox.nix @@ -13,7 +13,7 @@ in { xsession.windowManager.fluxbox = { enable = mkEnableOption "Fluxbox window manager"; - package = mkPackageOption pkgs "fluxbox" { }; + package = mkPackageOption pkgs "fluxbox" { nullable = true; }; init = mkOption { type = types.lines; @@ -95,7 +95,7 @@ in { platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.file = { ".fluxbox/init" = mkIf (cfg.init != "") { text = cfg.init; }; diff --git a/modules/services/window-managers/i3-sway/i3.nix b/modules/services/window-managers/i3-sway/i3.nix index 8c64aee44..eac5ef42e 100644 --- a/modules/services/window-managers/i3-sway/i3.nix +++ b/modules/services/window-managers/i3-sway/i3.nix @@ -208,7 +208,7 @@ in { xsession.windowManager.i3 = { enable = mkEnableOption "i3 window manager"; - package = mkPackageOption pkgs "i3" { }; + package = mkPackageOption pkgs "i3" { nullable = true; }; config = mkOption { type = types.nullOr configModule; @@ -232,7 +232,7 @@ in { platforms.linux) ]; - home.packages = [ cfg.package ]; + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; xsession.windowManager.command = "${cfg.package}/bin/i3"; diff --git a/modules/services/wlsunset.nix b/modules/services/wlsunset.nix index f3352750c..4bbd98e0b 100644 --- a/modules/services/wlsunset.nix +++ b/modules/services/wlsunset.nix @@ -128,6 +128,7 @@ in { systemd.user.services.wlsunset = { Unit = { Description = "Day/night gamma adjustments for Wayland compositors."; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/wluma.nix b/modules/services/wluma.nix new file mode 100644 index 000000000..1698b1387 --- /dev/null +++ b/modules/services/wluma.nix @@ -0,0 +1,103 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.services.wluma; + format = pkgs.formats.toml { }; + configFile = format.generate "config.toml" cfg.settings; +in { + meta.maintainers = with lib.maintainers; [ _0x5a4 ]; + + options.services.wluma = { + enable = lib.mkEnableOption + "Enable wluma, a service for automatic brightness adjustment"; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.wluma; + defaultText = lib.literalExpression "pkgs.wluma"; + description = "Package providing {command}`wluma`."; + }; + + settings = lib.mkOption { + type = format.type; + default = { }; + example = { + als.iio = { + path = ""; + thresholds = { + "0" = "night"; + "20" = "dark"; + "80" = "dim"; + "250" = "normal"; + "500" = "bright"; + "800" = "outdoors"; + }; + }; + }; + description = '' + Configuration to use for wluma. See + + for available options. + ''; + }; + + systemd.enable = lib.mkOption { + description = "Wluma systemd integration"; + type = lib.types.bool; + default = true; + }; + + systemd.target = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = config.wayland.systemd.target; + defaultText = lib.literalExpression "config.wayland.systemd.target"; + example = "sway-session.target"; + description = '' + The systemd target that will automatically start the Wluma service. + + When setting this value to `"sway-session.target"`, + make sure to also enable {option}`wayland.windowManager.sway.systemd.enable`, + otherwise the service may never be started. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "services.wluma" pkgs + lib.platforms.linux) + ]; + + home.packages = [ cfg.package ]; + + xdg.configFile = lib.mkIf (cfg.settings != { }) { + "wluma/config.toml".source = configFile; + }; + + systemd.user.services.wluma = lib.mkIf cfg.systemd.enable { + Unit = { + Description = + "Automatic brightness adjustment based on screen contents and ALS "; + After = [ cfg.systemd.target ]; + PartOf = [ cfg.systemd.target ]; + ConditionEnvironment = "WAYLAND_DISPLAY"; + X-Restart-Triggers = lib.mkIf (cfg.settings != { }) [ "${configFile}" ]; + }; + + Install.WantedBy = [ cfg.systemd.target ]; + + Service = { + ExecStart = lib.getExe cfg.package; + Restart = "always"; + + # Sandboxing. + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateUsers = true; + RestrictNamespaces = true; + SystemCallArchitectures = "native"; + SystemCallFilter = "@system-service"; + }; + }; + }; +} diff --git a/modules/services/wob.nix b/modules/services/wob.nix index d36565a00..d79338071 100644 --- a/modules/services/wob.nix +++ b/modules/services/wob.nix @@ -14,7 +14,7 @@ in { options.services.wob = { enable = mkEnableOption "wob"; - package = mkPackageOption pkgs "wob" { }; + package = mkPackageOption pkgs "wob" { nullable = true; }; settings = mkOption { type = settingsFormat.type; @@ -44,7 +44,7 @@ in { (lib.hm.assertions.assertPlatform "services.wob" pkgs lib.platforms.linux) ]; - systemd.user = mkIf cfg.systemd { + systemd.user = mkIf (cfg.systemd && (cfg.package != null)) { services.wob = { Unit = { Description = diff --git a/modules/services/wpaperd.nix b/modules/services/wpaperd.nix new file mode 100644 index 000000000..983687e6b --- /dev/null +++ b/modules/services/wpaperd.nix @@ -0,0 +1,84 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.wpaperd; + tomlFormat = pkgs.formats.toml { }; + inherit (lib) mkRenamedOptionModule mkIf; +in { + meta.maintainers = [ lib.hm.maintainers."3ulalia" ]; + + imports = [ + (mkRenamedOptionModule # \ + [ "programs" "wpaperd" "enable" ] # \ + [ "services" "wpaperd" "enable" ]) + (mkRenamedOptionModule # \ + [ "programs" "wpaperd" "package" ] # \ + [ "services" "wpaperd" "package" ]) + (mkRenamedOptionModule # \ + [ "programs" "wpaperd" "settings" ] # \ + [ "services" "wpaperd" "settings" ]) + ]; + + options.services.wpaperd = { + enable = lib.mkEnableOption "wpaperd"; + + package = lib.mkPackageOption pkgs "wpaperd" { nullable = true; }; + + settings = lib.mkOption { + type = tomlFormat.type; + default = { }; + example = lib.literalExpression '' + { + eDP-1 = { + path = "/home/foo/Pictures/Wallpaper"; + apply-shadow = true; + }; + DP-2 = { + path = "/home/foo/Pictures/Anime"; + sorting = "descending"; + }; + } + ''; + description = '' + Configuration written to + {file}`$XDG_CONFIG_HOME/wpaperd/wallpaper.toml`. + See + for the full list of options. + ''; + }; + }; + + config = mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "services.wpaperd" pkgs + lib.platforms.linux) + ]; + + home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + + xdg.configFile = { + "wpaperd/wallpaper.toml" = mkIf (cfg.settings != { }) { + source = tomlFormat.generate "wpaperd-wallpaper" cfg.settings; + }; + }; + + systemd.user.services.wpaperd = lib.mkIf (cfg.package != null) { + Install = { WantedBy = [ config.wayland.systemd.target ]; }; + + Unit = { + ConditionEnvironment = "WAYLAND_DISPLAY"; + Description = "wpaperd"; + PartOf = [ config.wayland.systemd.target ]; + After = [ config.wayland.systemd.target ]; + X-Restart-Triggers = + [ "${config.xdg.configFile."wpaperd/wallpaper.toml".source}" ]; + }; + + Service = { + ExecStart = "${lib.getExe cfg.package}"; + Restart = "always"; + RestartSec = "10"; + }; + }; + }; +} diff --git a/modules/services/xcape.nix b/modules/services/xcape.nix index 130db65b5..fa80607ce 100644 --- a/modules/services/xcape.nix +++ b/modules/services/xcape.nix @@ -60,11 +60,11 @@ in { Unit = mkMerge [ { Description = "xcape"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; } (mkIf (config.home.keyboard != null && config.home.keyboard != { }) { - After = [ "graphical-session-pre.target" "setxkbmap.service" ]; + After = [ "graphical-session.target" "setxkbmap.service" ]; }) ]; diff --git a/modules/services/xembed-sni-proxy.nix b/modules/services/xembed-sni-proxy.nix index 4273e81a3..dca6cebca 100644 --- a/modules/services/xembed-sni-proxy.nix +++ b/modules/services/xembed-sni-proxy.nix @@ -15,8 +15,8 @@ in { package = mkOption { type = types.package; - default = pkgs.plasma-workspace; - defaultText = literalExpression "pkgs.plasma-workspace"; + default = pkgs.kdePackages.plasma-workspace; + defaultText = literalExpression "pkgs.kdePackages.plasma-workspace"; description = '' Package containing the {command}`xembedsniproxy` program. @@ -34,7 +34,7 @@ in { systemd.user.services.xembed-sni-proxy = { Unit = { Description = "XEmbed SNI Proxy"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; diff --git a/modules/services/xidlehook.nix b/modules/services/xidlehook.nix index 2ce64e691..77b4c1dfe 100644 --- a/modules/services/xidlehook.nix +++ b/modules/services/xidlehook.nix @@ -151,7 +151,7 @@ in { Service = { Type = if cfg.once then "oneshot" else "simple"; ExecStart = "${script}"; - }; + } // lib.optionalAttrs (!cfg.once) { Restart = "always"; }; Install.WantedBy = [ "graphical-session.target" ]; }; }; diff --git a/modules/services/xscreensaver.nix b/modules/services/xscreensaver.nix index c5d6126be..0931f3d8a 100644 --- a/modules/services/xscreensaver.nix +++ b/modules/services/xscreensaver.nix @@ -50,7 +50,7 @@ in { systemd.user.services.xscreensaver = { Unit = { Description = "XScreenSaver"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; # Make sure the service is restarted if the settings change. diff --git a/modules/services/xsuspender.nix b/modules/services/xsuspender.nix index 058f15471..412f374c4 100644 --- a/modules/services/xsuspender.nix +++ b/modules/services/xsuspender.nix @@ -183,7 +183,7 @@ in { systemd.user.services.xsuspender = { Unit = { Description = "XSuspender"; - After = [ "graphical-session-pre.target" ]; + After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; X-Restart-Triggers = [ "${config.xdg.configFile."xsuspender.conf".source}" ]; diff --git a/modules/targets/darwin/fonts.nix b/modules/targets/darwin/fonts.nix index 988c5edc9..4c98f94d9 100644 --- a/modules/targets/darwin/fonts.nix +++ b/modules/targets/darwin/fonts.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, ... }: -with lib; - let homeDir = config.home.homeDirectory; fontsEnv = pkgs.buildEnv { @@ -13,13 +11,13 @@ let installDir = "${homeDir}/Library/Fonts/HomeManager"; in { # macOS won't recognize symlinked fonts - config = mkIf pkgs.stdenv.hostPlatform.isDarwin { + config = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin { home.file."Library/Fonts/.home-manager-fonts-version" = { text = "${fontsEnv}"; onChange = '' - run mkdir -p ${escapeShellArg installDir} + run mkdir -p ${lib.escapeShellArg installDir} run ${pkgs.rsync}/bin/rsync $VERBOSE_ARG -acL --chmod=u+w --delete \ - ${escapeShellArgs [ "${fonts}/" installDir ]} + ${lib.escapeShellArgs [ "${fonts}/" installDir ]} ''; }; }; diff --git a/modules/targets/darwin/keybindings.nix b/modules/targets/darwin/keybindings.nix index 96800073c..9d2c064c2 100644 --- a/modules/targets/darwin/keybindings.nix +++ b/modules/targets/darwin/keybindings.nix @@ -1,15 +1,13 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.targets.darwin; homeDir = config.home.homeDirectory; confFile = pkgs.writeText "DefaultKeybinding.dict" (lib.generators.toPlist { } cfg.keybindings); in { - options.targets.darwin.keybindings = mkOption { - type = with types; attrsOf anything; + options.targets.darwin.keybindings = lib.mkOption { + type = with lib.types; attrsOf anything; default = { }; example = { "^u" = "deleteToBeginningOfLine:"; @@ -28,15 +26,15 @@ in { ''; }; - config = mkIf (cfg.keybindings != { }) { + config = lib.mkIf (cfg.keybindings != { }) { assertions = [ - (hm.assertions.assertPlatform "targets.darwin.keybindings" pkgs - platforms.darwin) + (lib.hm.assertions.assertPlatform "targets.darwin.keybindings" pkgs + lib.platforms.darwin) ]; # NOTE: just copy the files because symlinks won't be recognized by macOS home.activation.setCocoaKeybindings = - hm.dag.entryAfter [ "writeBoundary" ] '' + lib.hm.dag.entryAfter [ "writeBoundary" ] '' verboseEcho "Configuring keybindings for the Cocoa Text System" run install -Dm644 $VERBOSE_ARG \ "${confFile}" "${homeDir}/Library/KeyBindings/DefaultKeyBinding.dict" diff --git a/modules/targets/darwin/linkapps.nix b/modules/targets/darwin/linkapps.nix index 0d434234b..caa461f45 100644 --- a/modules/targets/darwin/linkapps.nix +++ b/modules/targets/darwin/linkapps.nix @@ -1,9 +1,24 @@ { config, lib, pkgs, ... }: -{ - config = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin { +let cfg = config.targets.darwin; +in { + options.targets.darwin.linkApps = { + enable = + lib.mkEnableOption "linking macOS applications to the user environment" + // { + default = true; + }; + + directory = lib.mkOption { + type = lib.types.str; + default = "Applications/Home Manager Apps"; + description = "Path to link apps relative to the home directory."; + }; + }; + + config = lib.mkIf (pkgs.stdenv.hostPlatform.isDarwin && cfg.linkApps.enable) { # Install MacOS applications to the user environment. - home.file."Applications/Home Manager Apps".source = let + home.file.${cfg.linkApps.directory}.source = let apps = pkgs.buildEnv { name = "home-manager-applications"; paths = config.home.packages; diff --git a/modules/targets/darwin/search.nix b/modules/targets/darwin/search.nix index 8e0df3b20..9d82801bc 100644 --- a/modules/targets/darwin/search.nix +++ b/modules/targets/darwin/search.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.targets.darwin; searchEngines = { @@ -11,18 +9,18 @@ let Google = "com.google.www"; Yahoo = "com.yahoo.www"; }; - searchId = getAttr cfg.search searchEngines; + searchId = lib.getAttr cfg.search searchEngines; in { - options.targets.darwin.search = mkOption { - type = with types; nullOr (enum (attrNames searchEngines)); + options.targets.darwin.search = lib.mkOption { + type = with lib.types; nullOr (enum (lib.attrNames searchEngines)); default = null; description = "Default search engine."; }; - config = mkIf (cfg.search != null) { + config = lib.mkIf (cfg.search != null) { assertions = [ - (hm.assertions.assertPlatform "targets.darwin.search" pkgs - platforms.darwin) + (lib.hm.assertions.assertPlatform "targets.darwin.search" pkgs + lib.platforms.darwin) ]; targets.darwin.defaults = { diff --git a/modules/targets/darwin/user-defaults/default.nix b/modules/targets/darwin/user-defaults/default.nix index 97342d36b..9f1d35e6c 100644 --- a/modules/targets/darwin/user-defaults/default.nix +++ b/modules/targets/darwin/user-defaults/default.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.targets.darwin; @@ -13,27 +11,27 @@ let cliFlags = lib.optionalString isLocal "-currentHost"; toActivationCmd = domain: attrs: - "run /usr/bin/defaults ${cliFlags} import ${escapeShellArg domain} ${ - toDefaultsFile domain attrs - }"; + "run /usr/bin/defaults ${cliFlags} import ${ + lib.escapeShellArg domain + } ${toDefaultsFile domain attrs}"; nonNullDefaults = - mapAttrs (domain: attrs: (filterAttrs (n: v: v != null) attrs)) + lib.mapAttrs (domain: attrs: (lib.filterAttrs (n: v: v != null) attrs)) settings; writableDefaults = - filterAttrs (domain: attrs: attrs != { }) nonNullDefaults; - in mapAttrsToList toActivationCmd writableDefaults; + lib.filterAttrs (domain: attrs: attrs != { }) nonNullDefaults; + in lib.mapAttrsToList toActivationCmd writableDefaults; defaultsCmds = mkActivationCmds false cfg.defaults; currentHostDefaultsCmds = mkActivationCmds true cfg.currentHostDefaults; activationCmds = defaultsCmds ++ currentHostDefaultsCmds; in { - meta.maintainers = [ maintainers.midchildan ]; + meta.maintainers = [ lib.maintainers.midchildan ]; - options.targets.darwin.defaults = mkOption { - type = types.submodule ./opts-allhosts.nix; + options.targets.darwin.defaults = lib.mkOption { + type = lib.types.submodule ./opts-allhosts.nix; default = { }; example = { "com.apple.desktopservices" = { @@ -56,8 +54,8 @@ in { ''; }; - options.targets.darwin.currentHostDefaults = mkOption { - type = types.submodule ./opts-currenthost.nix; + options.targets.darwin.currentHostDefaults = lib.mkOption { + type = lib.types.submodule ./opts-currenthost.nix; default = { }; example = { "com.apple.controlcenter" = { BatteryShowPercentage = true; }; @@ -75,33 +73,34 @@ in { ''; }; - config = mkIf (activationCmds != [ ]) { + config = lib.mkIf (activationCmds != [ ]) { assertions = [ - (hm.assertions.assertPlatform "targets.darwin.defaults" pkgs - platforms.darwin) + (lib.hm.assertions.assertPlatform "targets.darwin.defaults" pkgs + lib.platforms.darwin) ]; warnings = let batteryOptionName = '' targets.darwin.currentHostDefaults."com.apple.controlcenter".BatteryShowPercentage''; batteryPercentage = - attrByPath [ "com.apple.menuextra.battery" "ShowPercent" ] null + lib.attrByPath [ "com.apple.menuextra.battery" "ShowPercent" ] null cfg.defaults; - webkitDevExtras = attrByPath [ + webkitDevExtras = lib.attrByPath [ "com.apple.Safari" "com.apple.Safari.ContentPageGroupIdentifier.WebKit2DeveloperExtrasEnabled" ] null cfg.defaults; - in optional (batteryPercentage != null) '' + in lib.optional (batteryPercentage != null) '' The option 'com.apple.menuextra.battery.ShowPercent' no longer works on macOS 11 and later. Instead, use '${batteryOptionName}'. - '' ++ optional (webkitDevExtras != null) '' + '' ++ lib.optional (webkitDevExtras != null) '' The option 'com.apple.Safari.com.apple.Safari.ContentPageGroupIdentifier.WebKit2DeveloperExtrasEnabled' is no longer present in recent versions of Safari. ''; - home.activation.setDarwinDefaults = hm.dag.entryAfter [ "writeBoundary" ] '' - verboseEcho "Configuring macOS user defaults" - ${concatStringsSep "\n" activationCmds} - ''; + home.activation.setDarwinDefaults = + lib.hm.dag.entryAfter [ "writeBoundary" ] '' + verboseEcho "Configuring macOS user defaults" + ${lib.concatStringsSep "\n" activationCmds} + ''; }; } diff --git a/modules/targets/darwin/user-defaults/opts-allhosts.nix b/modules/targets/darwin/user-defaults/opts-allhosts.nix index 4a4f10671..6d4307747 100644 --- a/modules/targets/darwin/user-defaults/opts-allhosts.nix +++ b/modules/targets/darwin/user-defaults/opts-allhosts.nix @@ -1,8 +1,8 @@ { config, lib, ... }: -with lib; - let + inherit (lib) types; + mkNullableOption = args: lib.mkOption (args // { type = types.nullOr args.type; @@ -284,12 +284,12 @@ in { }; config = { - "com.apple.Safari" = mkIf (safari.IncludeDevelopMenu != null) { + "com.apple.Safari" = lib.mkIf (safari.IncludeDevelopMenu != null) { WebKitDeveloperExtrasEnabledPreferenceKey = safari.IncludeDevelopMenu; "WebKitPreferences.developerExtrasEnabled" = safari.IncludeDevelopMenu; }; "com.apple.Safari.SandboxBroker" = - mkIf (safari.IncludeDevelopMenu != null) { + lib.mkIf (safari.IncludeDevelopMenu != null) { ShowDevelopMenu = safari.IncludeDevelopMenu; }; }; diff --git a/modules/targets/darwin/user-defaults/opts-currenthost.nix b/modules/targets/darwin/user-defaults/opts-currenthost.nix index 129f91487..61c2f8b3a 100644 --- a/modules/targets/darwin/user-defaults/opts-currenthost.nix +++ b/modules/targets/darwin/user-defaults/opts-currenthost.nix @@ -1,4 +1,4 @@ -{ config, lib, ... }: +{ lib, ... }: let mkNullableOption = args: diff --git a/modules/targets/generic-linux.nix b/modules/targets/generic-linux.nix index 9dce9f5c8..8503f58e8 100644 --- a/modules/targets/generic-linux.nix +++ b/modules/targets/generic-linux.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.targets.genericLinux; @@ -12,7 +10,7 @@ let in { imports = [ - (mkRenamedOptionModule [ "targets" "genericLinux" "extraXdgDataDirs" ] [ + (lib.mkRenamedOptionModule [ "targets" "genericLinux" "extraXdgDataDirs" ] [ "xdg" "systemDirs" "data" @@ -20,7 +18,7 @@ in { ]; options.targets.genericLinux = { - enable = mkEnableOption "" // { + enable = lib.mkEnableOption "" // { description = '' Whether to enable settings that make Home Manager work better on GNU/Linux distributions other than NixOS. @@ -28,9 +26,10 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ - (hm.assertions.assertPlatform "targets.genericLinux" pkgs platforms.linux) + (lib.hm.assertions.assertPlatform "targets.genericLinux" pkgs + lib.platforms.linux) ]; xdg.systemDirs.data = [ @@ -48,8 +47,8 @@ in { # We need to append system-wide FHS directories due to the default prefix # resolving to the Nix store. # https://github.com/nix-community/home-manager/pull/2891#issuecomment-1101064521 - home.sessionVariables = { - XCURSOR_PATH = "$XCURSOR_PATH\${XCURSOR_PATH:+:}" + concatStringsSep ":" [ + home.sessionSearchVariables = { + XCURSOR_PATH = [ "${config.home.profileDirectory}/share/icons" "/usr/share/icons" "/usr/share/pixmaps" @@ -93,7 +92,7 @@ in { # https://salsa.debian.org/debian/ncurses/-/blob/master/debian/rules # https://src.fedoraproject.org/rpms/ncurses/blob/main/f/ncurses.spec # https://gitweb.gentoo.org/repo/gentoo.git/tree/sys-libs/ncurses/ncurses-6.2-r1.ebuild - distroTerminfoDirs = concatStringsSep ":" [ + distroTerminfoDirs = lib.concatStringsSep ":" [ "/etc/terminfo" # debian, fedora, gentoo "/lib/terminfo" # debian "/usr/share/terminfo" # package default, all distros diff --git a/modules/xresources.nix b/modules/xresources.nix index a2396e236..91a872eb5 100644 --- a/modules/xresources.nix +++ b/modules/xresources.nix @@ -1,24 +1,23 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) mkOption types; cfg = config.xresources; formatLine = n: v: let formatList = x: - if isList x then + if lib.isList x then throw "can not convert 2-dimensional lists to Xresources format" else formatValue x; formatValue = v: - if isBool v then + if lib.isBool v then (if v then "true" else "false") - else if isList v then - concatMapStringsSep ", " formatList v + else if lib.isList v then + lib.concatMapStringsSep ", " formatList v else toString v; in "${n}: ${formatValue v}"; @@ -26,7 +25,7 @@ let xrdbMerge = "${pkgs.xorg.xrdb}/bin/xrdb -merge ${cfg.path}"; in { - meta.maintainers = [ maintainers.rycee ]; + meta.maintainers = [ lib.maintainers.rycee ]; options = { xresources.properties = mkOption { @@ -36,7 +35,7 @@ in { entry = either prim (listOf prim); in nullOr (attrsOf entry); default = null; - example = literalExpression '' + example = lib.literalExpression '' { "Emacs*toolBar" = 0; "XTerm*faceName" = "dejavu sans mono"; @@ -58,7 +57,7 @@ in { xresources.extraConfig = mkOption { type = types.lines; default = ""; - example = literalExpression '' + example = lib.literalExpression '' builtins.readFile ( pkgs.fetchFromGitHub { owner = "solarized"; @@ -85,13 +84,13 @@ in { }; }; - config = mkIf ((cfg.properties != null && cfg.properties != { }) + config = lib.mkIf ((cfg.properties != null && cfg.properties != { }) || cfg.extraConfig != "") { home.file.${cfg.path} = { - text = concatStringsSep "\n" ([ ] - ++ optional (cfg.extraConfig != "") cfg.extraConfig - ++ optionals (cfg.properties != null) - (mapAttrsToList formatLine cfg.properties)) + "\n"; + text = lib.concatStringsSep "\n" ([ ] + ++ lib.optional (cfg.extraConfig != "") cfg.extraConfig + ++ lib.optionals (cfg.properties != null) + (lib.mapAttrsToList formatLine cfg.properties)) + "\n"; onChange = '' if [[ -v DISPLAY ]]; then ${xrdbMerge} diff --git a/modules/xsession.nix b/modules/xsession.nix index edb99300e..6f13a854e 100644 --- a/modules/xsession.nix +++ b/modules/xsession.nix @@ -1,17 +1,16 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) mkOption types; cfg = config.xsession; in { - meta.maintainers = [ maintainers.rycee ]; + meta.maintainers = [ lib.maintainers.rycee ]; options = { xsession = { - enable = mkEnableOption "X Session"; + enable = lib.mkEnableOption "X Session"; trayTarget = mkOption { readOnly = true; @@ -49,7 +48,7 @@ in { windowManager.command = mkOption { type = types.str; - example = literalExpression '' + example = lib.literalExpression '' let xmonad = pkgs.xmonad-with-packages.override { packages = self: [ self.xmonad-contrib self.taffybar ]; @@ -92,7 +91,7 @@ in { importedVariables = mkOption { type = types.listOf (types.strMatching "[a-zA-Z_][a-zA-Z0-9_]*"); - apply = unique; + apply = lib.unique; example = [ "GDK_PIXBUF_ICON_LOADER" ]; visible = false; description = '' @@ -104,9 +103,10 @@ in { }; }; - config = mkIf cfg.enable { - assertions = - [ (hm.assertions.assertPlatform "xsession" pkgs platforms.linux) ]; + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "xsession" pkgs lib.platforms.linux) + ]; xsession.importedVariables = [ "DBUS_SESSION_BUS_ADDRESS" @@ -119,7 +119,7 @@ in { ]; systemd.user = { - services = mkIf (config.home.keyboard != null) { + services = lib.mkIf (config.home.keyboard != null) { setxkbmap = { Unit = { Description = "Set up keyboard in X"; @@ -134,9 +134,9 @@ in { RemainAfterExit = true; ExecStart = with config.home.keyboard; let - args = optional (layout != null) "-layout '${layout}'" - ++ optional (variant != null) "-variant '${variant}'" - ++ optional (model != null) "-model '${model}'" + args = lib.optional (layout != null) "-layout '${layout}'" + ++ lib.optional (variant != null) "-variant '${variant}'" + ++ lib.optional (model != null) "-model '${model}'" ++ [ "-option ''" ] ++ map (v: "-option '${v}'") options; in "${pkgs.xorg.setxkbmap}/bin/setxkbmap ${toString args}"; }; @@ -193,9 +193,9 @@ in { # script starts up graphical-session.target. systemctl --user stop graphical-session.target graphical-session-pre.target - ${optionalString (cfg.importedVariables != [ ]) + ${lib.optionalString (cfg.importedVariables != [ ]) ("systemctl --user import-environment " - + escapeShellArgs cfg.importedVariables)} + + lib.escapeShellArgs cfg.importedVariables)} ${cfg.profileExtra} @@ -224,9 +224,9 @@ in { sleep 0.5 done - ${optionalString (cfg.importedVariables != [ ]) + ${lib.optionalString (cfg.importedVariables != [ ]) ("systemctl --user unset-environment " - + escapeShellArgs cfg.importedVariables)} + + lib.escapeShellArgs cfg.importedVariables)} ''; }; }; diff --git a/nix-darwin/default.nix b/nix-darwin/default.nix index 018e9bab6..7dae50a5c 100644 --- a/nix-darwin/default.nix +++ b/nix-darwin/default.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.home-manager; @@ -9,14 +7,14 @@ let in { imports = [ ../nixos/common.nix ]; - config = mkMerge [ + config = lib.mkMerge [ { home-manager.extraSpecialArgs.darwinConfig = config; } - (mkIf (cfg.users != { }) { - system.activationScripts.postActivation.text = concatStringsSep "\n" - (mapAttrsToList (username: usercfg: '' - echo Activating home-manager configuration for ${username} - sudo -u ${username} --set-home ${ - pkgs.writeShellScript "activation-${username}" '' + (lib.mkIf (cfg.users != { }) { + system.activationScripts.postActivation.text = lib.concatStringsSep "\n" + (lib.mapAttrsToList (username: usercfg: '' + echo Activating home-manager configuration for ${usercfg.home.username} + sudo -u ${usercfg.home.username} --set-home ${ + pkgs.writeShellScript "activation-${usercfg.home.username}" '' ${lib.optionalString (cfg.backupFileExtension != null) "export HOME_MANAGER_BACKUP_EXT=${ lib.escapeShellArg cfg.backupFileExtension diff --git a/nixos/common.nix b/nixos/common.nix index ddf9a9359..05931ad60 100644 --- a/nixos/common.nix +++ b/nixos/common.nix @@ -3,9 +3,8 @@ { options, config, lib, pkgs, ... }: -with lib; - let + inherit (lib) flip mkOption mkEnableOption mkIf types; cfg = config.home-manager; @@ -74,7 +73,7 @@ in { extraSpecialArgs = mkOption { type = types.attrs; default = { }; - example = literalExpression "{ inherit emacs-overlay; }"; + example = lib.literalExpression "{ inherit emacs-overlay; }"; description = '' Extra `specialArgs` passed to Home Manager. This option can be used to pass additional arguments to all modules. @@ -84,7 +83,8 @@ in { sharedModules = mkOption { type = with types; listOf raw; default = [ ]; - example = literalExpression "[ { home.packages = [ nixpkgs-fmt ]; } ]"; + example = + lib.literalExpression "[ { home.packages = [ nixpkgs-fmt ]; } ]"; description = '' Extra modules added to all users. ''; @@ -103,19 +103,18 @@ in { }; }; - config = (mkMerge [ + config = (lib.mkMerge [ # Fix potential recursion when configuring home-manager users based on values in users.users #594 (mkIf (cfg.useUserPackages && cfg.users != { }) { - users.users = - (mapAttrs (username: usercfg: { packages = [ usercfg.home.path ]; }) - cfg.users); + users.users = (lib.mapAttrs + (_username: usercfg: { packages = [ usercfg.home.path ]; }) cfg.users); environment.pathsToLink = [ "/etc/profile.d" ]; }) (mkIf (cfg.users != { }) { - warnings = flatten (flip mapAttrsToList cfg.users (user: config: + warnings = lib.flatten (flip lib.mapAttrsToList cfg.users (user: config: flip map config.warnings (warning: "${user} profile: ${warning}"))); - assertions = flatten (flip mapAttrsToList cfg.users (user: config: + assertions = lib.flatten (flip lib.mapAttrsToList cfg.users (user: config: flip map config.assertions (assertion: { inherit (assertion) assertion; message = "${user} profile: ${assertion.message}"; diff --git a/nixos/default.nix b/nixos/default.nix index 4484d28f8..ee973146c 100644 --- a/nixos/default.nix +++ b/nixos/default.nix @@ -1,19 +1,17 @@ { config, lib, pkgs, utils, ... }: -with lib; - let cfg = config.home-manager; - serviceEnvironment = optionalAttrs (cfg.backupFileExtension != null) { + serviceEnvironment = lib.optionalAttrs (cfg.backupFileExtension != null) { HOME_MANAGER_BACKUP_EXT = cfg.backupFileExtension; - } // optionalAttrs cfg.verbose { VERBOSE = "1"; }; + } // lib.optionalAttrs cfg.verbose { VERBOSE = "1"; }; in { imports = [ ./common.nix ]; - config = mkMerge [ + config = lib.mkMerge [ { home-manager = { extraSpecialArgs.nixosConfig = config; @@ -33,10 +31,11 @@ in { }]; }; } - (mkIf (cfg.users != { }) { - systemd.services = mapAttrs' (_: usercfg: + (lib.mkIf (cfg.users != { }) { + systemd.services = lib.mapAttrs' (_: usercfg: let username = usercfg.home.username; - in nameValuePair ("home-manager-${utils.escapeSystemdPath username}") { + in lib.nameValuePair + "home-manager-${utils.escapeSystemdPath username}" { description = "Home Manager environment for ${username}"; wantedBy = [ "multi-user.target" ]; wants = [ "nix-daemon.socket" ]; @@ -61,7 +60,7 @@ in { sed = "${pkgs.gnused}/bin/sed"; - exportedSystemdVariables = concatStringsSep "|" [ + exportedSystemdVariables = lib.concatStringsSep "|" [ "DBUS_SESSION_BUS_ADDRESS" "DISPLAY" "WAYLAND_DISPLAY" diff --git a/tests/asserts.nix b/tests/asserts.nix index 1909f90b7..0d4f50307 100644 --- a/tests/asserts.nix +++ b/tests/asserts.nix @@ -1,8 +1,6 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, lib, ... }: +let inherit (lib) concatStringsSep mkOption types; +in { options.test.asserts = { warnings = { enable = mkOption { @@ -37,8 +35,8 @@ with lib; }; }; - config = mkMerge [ - (mkIf config.test.asserts.warnings.enable { + config = lib.mkMerge [ + (lib.mkIf config.test.asserts.warnings.enable { home.file = { "asserts/warnings.actual".text = concatStringsSep '' @@ -57,12 +55,13 @@ with lib; ''; }) - (mkIf config.test.asserts.assertions.enable { + (lib.mkIf config.test.asserts.assertions.enable { home.file = { "asserts/assertions.actual".text = concatStringsSep '' -- - '' (map (x: x.message) (filter (x: !x.assertion) config.assertions)); + '' + (map (x: x.message) (lib.filter (x: !x.assertion) config.assertions)); "asserts/assertions.expected".text = concatStringsSep '' -- diff --git a/tests/default.nix b/tests/default.nix index a3d5749df..04d7b1c52 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -14,35 +14,33 @@ let # `"@package-name@"`. This allows the tests to refer to derivations through # their values without establishing an actual dependency on the derivation # output. - scrubDerivations = attrs: + scrubDerivation = name: value: let - scrubDerivation = name: value: - let - scrubbedValue = scrubDerivations value; + scrubbedValue = scrubDerivations value; - newDrvAttrs = { - buildScript = abort "no build allowed"; + newDrvAttrs = { + buildScript = abort "no build allowed"; - outPath = builtins.traceVerbose ("${name} - got out path") - "@${lib.getName value}@"; + outPath = builtins.traceVerbose "${name} - got out path" + "@${lib.getName value}@"; - # Prevent getOutput from descending into outputs - outputSpecified = true; + # Prevent getOutput from descending into outputs + outputSpecified = true; - # Allow the original package to be used in derivation inputs - __spliced = { - buildHost = value; - hostTarget = value; - }; - }; - in if lib.isAttrs value then - if lib.isDerivation value then - scrubbedValue // newDrvAttrs - else - scrubbedValue - else - value; - in lib.mapAttrs scrubDerivation attrs; + # Allow the original package to be used in derivation inputs + __spliced = { + buildHost = value; + hostTarget = value; + }; + }; + in if lib.isAttrs value then + if lib.isDerivation value then + scrubbedValue // newDrvAttrs + else + scrubbedValue + else + value; + scrubDerivations = attrs: let in lib.mapAttrs scrubDerivation attrs; # Globally unscrub a few selected packages that are used by a wide selection of tests. whitelist = let @@ -63,10 +61,165 @@ let }; in outer; + # TODO: figure out stdenv stubbing so we don't have to do this + darwinBlacklist = let + # List of packages that need to be scrubbed on Darwin + # Packages are scrubbed in linux and expected in test output + packagesToScrub = [ + "aerc" + "alot" + "antidote" + "aria2" + "atuin" + "autojump" + "bacon" + "bash" + "bash-completion" + "bat" + "borgmatic" + "bottom" + "broot" + "browserpass" + "btop" + "carapace" + "cava" + "cmus" + "comodoro" + "darcs" + "dircolors" + "delta" + "direnv" + "earthly" + "emacs" + "espanso" + "fastfetch" + "feh" + "gallery-dl" + "gh" + "gh-dash" + "ghostty" + "git" + "git-cliff" + "git-credential-oauth" + "git-worktree-switcher" + "gnupg" + "go" + "granted" + "helix" + "himalaya" + "htop" + "hyfetch" + "i3status" + "irssi" + "jankyborders" + "jujutsu" + "joplin-desktop" + "jqp" + "k9s" + "kakoune" + "khal" + "khard" + "kitty" + "kubecolor" + "lapce" + "lazydocker" + "lazygit" + "ledger" + "less" + "lesspipe" + "lf" + "lsd" + "lieer" + "mbsync" + "mergiraf" + "micro" + "mise" + "mpv" + "mu" + "mujmap" + "msmtp" + "ne" + "neomutt" + "neovide" + "nheko" + "nix" + "nix-index" + "nix-your-shell" + "ollama" + "onlyoffice-desktopeditors" + "openstackclient" + "papis" + "pay-respects" + "pet" + "pistol" + "pls" + "poetry" + "powerline-go" + "pubs" + "pyenv" + "qcal" + "qutebrowser" + "ranger" + "rio" + "ripgrep" + "ruff" + "sage" + "sapling" + "sbt" + "scmpuff" + "senpai" + "sftpman" + "sioyek" + "skhd" + "sm64ex" + "spotify-player" + "starship" + "taskwarrior" + "tealdeer" + "texlive" + "thefuck" + "thunderbird" + "tmate" + "topgrade" + "translate-shell" + "vifm" + "vim-vint" + "vscode" + "watson" + "wezterm" + "yazi" + "yubikey-agent" + "zed-editor" + "zellij" + "zk" + "zplug" + "zsh" + ]; + + inner = self: super: + lib.mapAttrs (name: value: + if lib.elem name packagesToScrub then + # Apply scrubbing to this specific package + scrubDerivation name value + else + value) super; + + outer = self: super: + inner self super // { + buildPackages = super.buildPackages.extend inner; + }; + in outer; + scrubbedPkgs = - let rawScrubbedPkgs = lib.makeExtensible (final: scrubDerivations pkgs); - in builtins.traceVerbose "eval scrubbed nixpkgs" - (rawScrubbedPkgs.extend whitelist); + # TODO: fix darwin stdenv stubbing + if isDarwin then + let rawPkgs = lib.makeExtensible (final: pkgs); + in builtins.traceVerbose "eval scrubbed darwin nixpkgs" + (rawPkgs.extend darwinBlacklist) + else + let rawScrubbedPkgs = lib.makeExtensible (final: scrubDerivations pkgs); + in builtins.traceVerbose "eval scrubbed nixpkgs" + (rawScrubbedPkgs.extend whitelist); modules = import ../modules/modules.nix { inherit lib pkgs; @@ -92,7 +245,7 @@ let # Fix impurities. Without these some of the user's environment # will leak into the tests through `builtins.getEnv`. - xdg.enable = true; + xdg.enable = lib.mkDefault true; home = { username = "hm-user"; homeDirectory = "/home/hm-user"; @@ -124,6 +277,7 @@ in import nmtSrc { ./modules/misc/manual ./modules/misc/nix ./modules/misc/specialisation + ./modules/misc/xdg ./modules/programs/aerc ./modules/programs/alacritty ./modules/programs/alot @@ -146,6 +300,7 @@ in import nmtSrc { ./modules/programs/darcs ./modules/programs/dircolors ./modules/programs/direnv + ./modules/programs/earthly ./modules/programs/emacs ./modules/programs/fastfetch ./modules/programs/feh @@ -170,6 +325,7 @@ in import nmtSrc { ./modules/programs/irssi ./modules/programs/jujutsu ./modules/programs/joplin-desktop + ./modules/programs/jqp ./modules/programs/k9s ./modules/programs/kakoune ./modules/programs/khal @@ -178,6 +334,7 @@ in import nmtSrc { ./modules/programs/kubecolor ./modules/programs/lapce ./modules/programs/ledger + ./modules/programs/lazydocker ./modules/programs/less ./modules/programs/lesspipe ./modules/programs/lf @@ -185,8 +342,10 @@ in import nmtSrc { ./modules/programs/lieer ./modules/programs/man ./modules/programs/mbsync + ./modules/programs/mergiraf ./modules/programs/micro ./modules/programs/mise + ./modules/programs/mods ./modules/programs/mpv ./modules/programs/mu ./modules/programs/mujmap @@ -202,6 +361,7 @@ in import nmtSrc { ./modules/programs/nnn ./modules/programs/nushell ./modules/programs/oh-my-posh + ./modules/programs/onlyoffice ./modules/programs/openstackclient ./modules/programs/pandoc ./modules/programs/papis @@ -219,6 +379,7 @@ in import nmtSrc { ./modules/programs/readline ./modules/programs/rio ./modules/programs/ripgrep + ./modules/programs/ripgrep-all ./modules/programs/ruff ./modules/programs/sagemath ./modules/programs/sapling @@ -233,6 +394,7 @@ in import nmtSrc { ./modules/programs/starship ./modules/programs/taskwarrior ./modules/programs/tealdeer + ./modules/programs/tex-fmt ./modules/programs/texlive ./modules/programs/thefuck ./modules/programs/thunderbird @@ -261,11 +423,15 @@ in import nmtSrc { ./modules/services/espanso-darwin ./modules/services/git-sync-darwin ./modules/services/imapnotify-darwin + ./modules/services/jankyborders + ./modules/services/macos-remap-keys ./modules/services/nix-gc-darwin ./modules/services/ollama/darwin + ./modules/services/skhd ./modules/services/yubikey-agent-darwin ./modules/targets-darwin ] ++ lib.optionals isLinux [ + ./modules/misc/xdg/linux.nix ./modules/config/home-cursor ./modules/config/i18n ./modules/i18n/input-method @@ -275,7 +441,6 @@ in import nmtSrc { ./modules/misc/numlock ./modules/misc/pam ./modules/misc/qt - ./modules/misc/xdg ./modules/misc/xsession ./modules/programs/abook ./modules/programs/autorandr @@ -284,9 +449,12 @@ in import nmtSrc { ./modules/programs/bemenu ./modules/programs/boxxy ./modules/programs/cavalier + ./modules/programs/distrobox ./modules/programs/eww + ./modules/programs/firefox ./modules/programs/firefox/firefox.nix ./modules/programs/firefox/floorp.nix + ./modules/programs/firefox/librewolf.nix ./modules/programs/foot ./modules/programs/freetube ./modules/programs/fuzzel @@ -306,14 +474,15 @@ in import nmtSrc { ./modules/programs/rbw ./modules/programs/rofi ./modules/programs/rofi-pass + ./modules/programs/swayimg ./modules/programs/swaylock ./modules/programs/swayr ./modules/programs/terminator ./modules/programs/tofi + ./modules/programs/vinegar ./modules/programs/waybar ./modules/programs/wlogout ./modules/programs/wofi - ./modules/programs/wpaperd ./modules/programs/xmobar ./modules/programs/yambar ./modules/programs/yt-dlp @@ -325,12 +494,15 @@ in import nmtSrc { ./modules/services/cachix-agent ./modules/services/cliphist ./modules/services/clipman + ./modules/services/clipse ./modules/services/comodoro ./modules/services/copyq ./modules/services/conky ./modules/services/darkman + ./modules/services/davmail ./modules/services/devilspie2 ./modules/services/dropbox + ./modules/services/easyeffects ./modules/services/emacs ./modules/services/espanso ./modules/services/flameshot @@ -343,14 +515,17 @@ in import nmtSrc { ./modules/services/home-manager-auto-upgrade ./modules/services/hypridle ./modules/services/hyprpaper + ./modules/services/hyprpolkitagent ./modules/services/imapnotify ./modules/services/kanshi ./modules/services/lieer ./modules/services/linux-wallpaperengine + ./modules/services/lxqt-policykit-agent ./modules/services/mopidy ./modules/services/mpd ./modules/services/mpd-mpris ./modules/services/mpdris2 + ./modules/services/mpdscribble ./modules/services/nix-gc ./modules/services/ollama/linux ./modules/services/osmscout-server @@ -362,6 +537,7 @@ in import nmtSrc { ./modules/services/picom ./modules/services/playerctld ./modules/services/podman-linux + ./modules/services/polkit-gnome ./modules/services/polybar ./modules/services/recoll ./modules/services/redshift-gammastep @@ -372,6 +548,7 @@ in import nmtSrc { ./modules/services/swayidle ./modules/services/swaync ./modules/services/swayosd + ./modules/services/swww ./modules/services/sxhkd ./modules/services/syncthing/linux ./modules/services/tldr-update @@ -390,6 +567,7 @@ in import nmtSrc { ./modules/services/window-managers/wayfire ./modules/services/wlsunset ./modules/services/wob + ./modules/services/wpaperd ./modules/services/xsettingsd ./modules/services/yubikey-agent ./modules/systemd diff --git a/tests/integration/default.nix b/tests/integration/default.nix index 4fbaaf7af..e3ac0bed8 100644 --- a/tests/integration/default.nix +++ b/tests/integration/default.nix @@ -15,6 +15,7 @@ let mu = runTest ./standalone/mu; nh = runTest ./standalone/nh.nix; nixos-basics = runTest ./nixos/basics.nix; + rclone = runTest ./standalone/rclone; standalone-flake-basics = runTest ./standalone/flake-basics.nix; standalone-standard-basics = runTest ./standalone/standard-basics.nix; }; diff --git a/tests/integration/standalone/kitty-theme-bad-home.nix b/tests/integration/standalone/kitty-theme-bad-home.nix index 4c4594173..ca1a1289f 100644 --- a/tests/integration/standalone/kitty-theme-bad-home.nix +++ b/tests/integration/standalone/kitty-theme-bad-home.nix @@ -1,4 +1,4 @@ -{ ... }: { +{ home.username = "alice"; home.homeDirectory = "/home/alice"; home.stateVersion = "24.11"; diff --git a/tests/integration/standalone/kitty-theme-good-home.nix b/tests/integration/standalone/kitty-theme-good-home.nix index 606724bab..23eaacbfb 100644 --- a/tests/integration/standalone/kitty-theme-good-home.nix +++ b/tests/integration/standalone/kitty-theme-good-home.nix @@ -1,4 +1,4 @@ -{ ... }: { +{ home.username = "alice"; home.homeDirectory = "/home/alice"; diff --git a/tests/integration/standalone/rclone/default.nix b/tests/integration/standalone/rclone/default.nix new file mode 100644 index 000000000..75b5e6ff0 --- /dev/null +++ b/tests/integration/standalone/rclone/default.nix @@ -0,0 +1,120 @@ +{ pkgs, ... }: + +{ + name = "rclone"; + + nodes.machine = { ... }: { + imports = [ "${pkgs.path}/nixos/modules/installer/cd-dvd/channel.nix" ]; + virtualisation.memorySize = 2048; + users.users.alice = { + isNormalUser = true; + description = "Alice Foobar"; + password = "foobar"; + uid = 1000; + }; + }; + + testScript = '' + start_all() + machine.wait_for_unit("network.target") + machine.wait_for_unit("multi-user.target") + + home_manager = "${../../../..}" + + def login_as_alice(): + machine.wait_until_tty_matches("1", "login: ") + machine.send_chars("alice\n") + machine.wait_until_tty_matches("1", "Password: ") + machine.send_chars("foobar\n") + machine.wait_until_tty_matches("1", "alice\\@machine") + + def logout_alice(): + machine.send_chars("exit\n") + + def alice_cmd(cmd): + return f"su -l alice --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" + + def succeed_as_alice(*cmds): + return machine.succeed(*map(alice_cmd,cmds)) + + def fail_as_alice(*cmds): + return machine.fail(*map(alice_cmd,cmds)) + + # Create a persistent login so that Alice has a systemd session. + login_as_alice() + + # Set up a home-manager channel. + succeed_as_alice(" ; ".join([ + "mkdir -p /home/alice/.nix-defexpr/channels", + f"ln -s {home_manager} /home/alice/.nix-defexpr/channels/home-manager" + ])) + + with subtest("Home Manager installation"): + succeed_as_alice("nix-shell \"\" -A install") + + succeed_as_alice("cp ${ + ./home.nix + } /home/alice/.config/home-manager/home.nix") + + with subtest("Generate with no secrets"): + succeed_as_alice("install -m644 ${ + ./no-secrets.nix + } /home/alice/.config/home-manager/test-remote.nix") + + actual = succeed_as_alice("home-manager switch") + expected = "Activating createRcloneConfig" + assert expected in actual, \ + f"expected home-manager switch to contain {expected}, but got {actual}" + + succeed_as_alice("diff -u ${ + ./no-secrets.conf + } /home/alice/.config/rclone/rclone.conf") + + with subtest("Generate with secrets from store"): + succeed_as_alice("install -m644 ${ + ./with-secrets-in-store.nix + } /home/alice/.config/home-manager/test-remote.nix") + + actual = succeed_as_alice("home-manager switch") + expected = "Activating createRcloneConfig" + assert expected in actual, \ + f"expected home-manager switch to contain {expected}, but got {actual}" + + succeed_as_alice("diff -u ${ + ./with-secrets-in-store.conf + } /home/alice/.config/rclone/rclone.conf") + + with subtest("Secrets with spaces"): + succeed_as_alice("install -m644 ${ + ./secrets-with-whitespace.nix + } /home/alice/.config/home-manager/test-remote.nix") + + actual = succeed_as_alice("home-manager switch") + expected = "Activating createRcloneConfig" + assert expected in actual, \ + f"expected home-manager switch to contain {expected}, but got {actual}" + + succeed_as_alice("diff -u ${ + ./secrets-with-whitespace.conf + } /home/alice/.config/rclone/rclone.conf") + + with subtest("Un-typed remote"): + succeed_as_alice("install -m644 ${ + ./no-type.nix + } /home/alice/.config/home-manager/test-remote.nix") + + actual = fail_as_alice("home-manager switch") + expected = "Activating createRcloneConfig" + assert expected not in actual, \ + f"expected home-manager switch to contain {expected}, but got {actual}" + + expected = "An attribute set containing a remote type and options." + assert expected not in actual, \ + f"expected home-manager switch to contain {expected}, but got {actual}" + + + # TODO: verify correct activation order with the agenix and sops hm modules + + logout_alice() + ''; +} diff --git a/tests/integration/standalone/rclone/home.nix b/tests/integration/standalone/rclone/home.nix new file mode 100644 index 000000000..0bc0f8a51 --- /dev/null +++ b/tests/integration/standalone/rclone/home.nix @@ -0,0 +1,13 @@ +{ + imports = [ ./test-remote.nix ]; + + home.username = "alice"; + home.homeDirectory = "/home/alice"; + + home.stateVersion = "24.05"; # Please read the comment before changing. + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; + + programs.rclone.enable = true; +} diff --git a/tests/integration/standalone/rclone/no-secrets.conf b/tests/integration/standalone/rclone/no-secrets.conf new file mode 100644 index 000000000..d1fc379a1 --- /dev/null +++ b/tests/integration/standalone/rclone/no-secrets.conf @@ -0,0 +1,5 @@ +[alices-cool-remote] +host=backup-server +key_file=/key/path/foo +type=sftp +user=alice diff --git a/tests/integration/standalone/rclone/no-secrets.nix b/tests/integration/standalone/rclone/no-secrets.nix new file mode 100644 index 000000000..077a7ff15 --- /dev/null +++ b/tests/integration/standalone/rclone/no-secrets.nix @@ -0,0 +1,10 @@ +{ + programs.rclone.remotes = { + alices-cool-remote.config = { + type = "sftp"; + host = "backup-server"; + user = "alice"; + key_file = "/key/path/foo"; + }; + }; +} diff --git a/tests/integration/standalone/rclone/no-type.nix b/tests/integration/standalone/rclone/no-type.nix new file mode 100644 index 000000000..bce7adc2e --- /dev/null +++ b/tests/integration/standalone/rclone/no-type.nix @@ -0,0 +1,9 @@ +{ + programs.rclone.remotes = { + alices-cool-remote-v4.config = { + description = "this value does not have a type"; + some-key = "value pairs"; + another-key-value = "pair"; + }; + }; +} diff --git a/tests/integration/standalone/rclone/secrets-with-whitespace.conf b/tests/integration/standalone/rclone/secrets-with-whitespace.conf new file mode 100644 index 000000000..8506d12c1 --- /dev/null +++ b/tests/integration/standalone/rclone/secrets-with-whitespace.conf @@ -0,0 +1,5 @@ +[alices-cool-remote-v3] +description = alices speeedy remote +type = memory +spaces-secret = This is a secret with spaces, it has single spaces, and lots of spaces :3 + diff --git a/tests/integration/standalone/rclone/secrets-with-whitespace.nix b/tests/integration/standalone/rclone/secrets-with-whitespace.nix new file mode 100644 index 000000000..860778c2b --- /dev/null +++ b/tests/integration/standalone/rclone/secrets-with-whitespace.nix @@ -0,0 +1,13 @@ +{ pkgs, ... }: { + programs.rclone.remotes = { + alices-cool-remote-v3 = { + config = { + type = "memory"; + description = "alices speeedy remote"; + }; + secrets.spaces-secret = "${pkgs.writeText "secret" '' + This is a secret with spaces, it has single spaces, and lots of spaces :3 + ''}"; + }; + }; +} diff --git a/tests/integration/standalone/rclone/with-secrets-in-store.conf b/tests/integration/standalone/rclone/with-secrets-in-store.conf new file mode 100644 index 000000000..12e2777d1 --- /dev/null +++ b/tests/integration/standalone/rclone/with-secrets-in-store.conf @@ -0,0 +1,6 @@ +[alices-cool-remote-v2] +hard_delete = true +type = b2 +account = super-secret-account-id +key = api-key-from-file + diff --git a/tests/integration/standalone/rclone/with-secrets-in-store.nix b/tests/integration/standalone/rclone/with-secrets-in-store.nix new file mode 100644 index 000000000..4c47a60e2 --- /dev/null +++ b/tests/integration/standalone/rclone/with-secrets-in-store.nix @@ -0,0 +1,18 @@ +{ pkgs, ... }: { + programs.rclone.remotes = { + alices-cool-remote-v2 = { + config = { + type = "b2"; + hard_delete = true; + }; + secrets = { + account = "${pkgs.writeText "acc" '' + super-secret-account-id + ''}"; + key = "${pkgs.writeText "key" '' + api-key-from-file + ''}"; + }; + }; + }; +} diff --git a/tests/modules/accounts/email-test-accounts.nix b/tests/modules/accounts/email-test-accounts.nix index e66e58949..44614733e 100644 --- a/tests/modules/accounts/email-test-accounts.nix +++ b/tests/modules/accounts/email-test-accounts.nix @@ -1,5 +1,3 @@ -{ ... }: - { accounts.email = { maildirBasePath = "Mail"; diff --git a/tests/modules/config/home-cursor/default.nix b/tests/modules/config/home-cursor/default.nix index 08cde5452..7cef6bae6 100644 --- a/tests/modules/config/home-cursor/default.nix +++ b/tests/modules/config/home-cursor/default.nix @@ -34,6 +34,126 @@ home.stateVersion = "24.11"; + test.asserts.warnings.expected = ['' + Setting home.pointerCursor to null is deprecated. + Please update your configuration to explicitly set: + + home.pointerCursor.enable = false; + '']; + + nmt.script = '' + assertPathNotExists home-path/share/icons/catppuccin-macchiato-blue-cursors/index.theme + + hmEnvFile=home-path/etc/profile.d/hm-session-vars.sh + assertFileExists $hmEnvFile + assertFileNotRegex $hmEnvFile 'XCURSOR_THEME="catppuccin-macchiato-blue-standard"' + assertFileNotRegex $hmEnvFile 'XCURSOR_SIZE="32"' + assertFileNotRegex $hmEnvFile 'HYPRCURSOR_THEME="catppuccin-macchiato-blue-standard"' + assertFileNotRegex $hmEnvFile 'HYPRCURSOR_SIZE="32"' + ''; + }; + }; + + home-cursor-legacy-disabled-with-enable = { realPkgs, ... }: { + config = { + home.pointerCursor = { + enable = false; + package = realPkgs.catppuccin-cursors.macchiatoBlue; + name = "catppuccin-macchiato-blue-standard"; + size = 64; + gtk.enable = true; + hyprcursor.enable = true; + x11.enable = true; + }; + + home.stateVersion = "24.11"; + + nmt.script = '' + assertPathNotExists home-path/share/icons/catppuccin-macchiato-blue-cursors/index.theme + + hmEnvFile=home-path/etc/profile.d/hm-session-vars.sh + assertFileExists $hmEnvFile + assertFileNotRegex $hmEnvFile 'XCURSOR_THEME="catppuccin-macchiato-blue-standard"' + assertFileNotRegex $hmEnvFile 'XCURSOR_SIZE="32"' + assertFileNotRegex $hmEnvFile 'HYPRCURSOR_THEME="catppuccin-macchiato-blue-standard"' + assertFileNotRegex $hmEnvFile 'HYPRCURSOR_SIZE="32"' + ''; + }; + }; + + home-cursor-legacy-enabled-with-enable = { realPkgs, ... }: { + config = { + home.pointerCursor = { + enable = true; + package = realPkgs.catppuccin-cursors.macchiatoBlue; + name = "catppuccin-macchiato-blue-standard"; + size = 64; + gtk.enable = true; + hyprcursor.enable = true; + x11.enable = true; + }; + + home.stateVersion = "24.11"; + + nmt.script = '' + assertFileContent \ + home-path/share/icons/catppuccin-macchiato-blue-cursors/index.theme \ + ${./expected-index.theme} + + hmEnvFile=home-path/etc/profile.d/hm-session-vars.sh + assertFileExists $hmEnvFile + assertFileRegex $hmEnvFile 'XCURSOR_THEME="catppuccin-macchiato-blue-standard"' + assertFileRegex $hmEnvFile 'XCURSOR_SIZE="64"' + assertFileRegex $hmEnvFile 'HYPRCURSOR_THEME="catppuccin-macchiato-blue-standard"' + assertFileRegex $hmEnvFile 'HYPRCURSOR_SIZE="64"' + ''; + + }; + }; + + home-cursor = { realPkgs, ... }: { + config = { + home.pointerCursor = { + enable = true; + package = realPkgs.catppuccin-cursors.macchiatoBlue; + name = "catppuccin-macchiato-blue-standard"; + size = 64; + gtk.enable = true; + hyprcursor.enable = true; + x11.enable = true; + }; + + home.stateVersion = "25.05"; + + nmt.script = '' + assertFileContent \ + home-path/share/icons/catppuccin-macchiato-blue-cursors/index.theme \ + ${./expected-index.theme} + + hmEnvFile=home-path/etc/profile.d/hm-session-vars.sh + assertFileExists $hmEnvFile + assertFileRegex $hmEnvFile 'XCURSOR_THEME="catppuccin-macchiato-blue-standard"' + assertFileRegex $hmEnvFile 'XCURSOR_SIZE="64"' + assertFileRegex $hmEnvFile 'HYPRCURSOR_THEME="catppuccin-macchiato-blue-standard"' + assertFileRegex $hmEnvFile 'HYPRCURSOR_SIZE="64"' + ''; + }; + }; + + home-cursor-disabled = { realPkgs, ... }: { + config = { + home.pointerCursor = { + enable = false; + package = realPkgs.catppuccin-cursors.macchiatoBlue; + name = "catppuccin-macchiato-blue-standard"; + size = 64; + gtk.enable = true; + hyprcursor.enable = true; + x11.enable = true; + }; + + home.stateVersion = "25.05"; + nmt.script = '' assertPathNotExists home-path/share/icons/catppuccin-macchiato-blue-cursors/index.theme diff --git a/tests/modules/files/disabled.nix b/tests/modules/files/disabled.nix index b9ed858aa..d106f26bd 100644 --- a/tests/modules/files/disabled.nix +++ b/tests/modules/files/disabled.nix @@ -1,5 +1,3 @@ -{ ... }: - { home.file."disabled" = { enable = false; diff --git a/tests/modules/files/executable.nix b/tests/modules/files/executable.nix index 9ab8f3591..0e144ed48 100644 --- a/tests/modules/files/executable.nix +++ b/tests/modules/files/executable.nix @@ -1,5 +1,3 @@ -{ ... }: - { home.file."executable" = { text = ""; diff --git a/tests/modules/files/hidden-source.nix b/tests/modules/files/hidden-source.nix index 380a2cb2d..6c205b481 100644 --- a/tests/modules/files/hidden-source.nix +++ b/tests/modules/files/hidden-source.nix @@ -1,5 +1,3 @@ -{ ... }: - { home.file.".hidden".source = ./.hidden; diff --git a/tests/modules/files/source-with-spaces.nix b/tests/modules/files/source-with-spaces.nix index cd78664e5..a854caf64 100644 --- a/tests/modules/files/source-with-spaces.nix +++ b/tests/modules/files/source-with-spaces.nix @@ -1,5 +1,3 @@ -{ ... }: - { home.file."source with spaces!".source = ./. + "/source with spaces!"; diff --git a/tests/modules/files/target-conflict.nix b/tests/modules/files/target-conflict.nix index 9677cf9de..34f1a34d2 100644 --- a/tests/modules/files/target-conflict.nix +++ b/tests/modules/files/target-conflict.nix @@ -1,5 +1,3 @@ -{ ... }: - { home.file = { conflict1 = { diff --git a/tests/modules/files/target-with-shellvar.nix b/tests/modules/files/target-with-shellvar.nix index 59fc02fde..317db5b21 100644 --- a/tests/modules/files/target-with-shellvar.nix +++ b/tests/modules/files/target-with-shellvar.nix @@ -1,5 +1,3 @@ -{ ... }: - { home.file."$HOME/$FOO/bar baz".text = "blah"; diff --git a/tests/modules/files/text.nix b/tests/modules/files/text.nix index c09c56c4a..70bbc438f 100644 --- a/tests/modules/files/text.nix +++ b/tests/modules/files/text.nix @@ -1,5 +1,3 @@ -{ ... }: - { home.file."using-text".text = '' This is the diff --git a/tests/modules/home-environment/default.nix b/tests/modules/home-environment/default.nix index e76e248a1..c38ad5ce5 100644 --- a/tests/modules/home-environment/default.nix +++ b/tests/modules/home-environment/default.nix @@ -1,4 +1,5 @@ { - home-session-variables = ./session-variables.nix; home-session-path = ./session-path.nix; + home-session-search-variables = ./session-search-variables.nix; + home-session-variables = ./session-variables.nix; } diff --git a/tests/modules/home-environment/session-path.nix b/tests/modules/home-environment/session-path.nix index 57cfeceda..907d6c398 100644 --- a/tests/modules/home-environment/session-path.nix +++ b/tests/modules/home-environment/session-path.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ ... }: { imports = [ @@ -10,6 +10,6 @@ hmSessVars=home-path/etc/profile.d/hm-session-vars.sh assertFileExists $hmSessVars assertFileContains $hmSessVars \ - 'export PATH="$PATH''${PATH:+:}bar:baz:foo"' + 'export PATH="bar:baz:foo''${PATH:+:}$PATH"' ''; } diff --git a/tests/modules/home-environment/session-search-variables.nix b/tests/modules/home-environment/session-search-variables.nix new file mode 100644 index 000000000..b12009f2b --- /dev/null +++ b/tests/modules/home-environment/session-search-variables.nix @@ -0,0 +1,15 @@ +{ ... }: + +{ + imports = [ + ({ ... }: { config.home.sessionSearchVariables.TEST = [ "foo" ]; }) + ({ ... }: { config.home.sessionSearchVariables.TEST = [ "bar" "baz" ]; }) + ]; + + nmt.script = '' + hmSessVars=home-path/etc/profile.d/hm-session-vars.sh + assertFileExists $hmSessVars + assertFileContains $hmSessVars \ + 'export TEST="bar:baz:foo''${TEST:+:}$TEST"' + ''; +} diff --git a/tests/modules/home-environment/session-variables.nix b/tests/modules/home-environment/session-variables.nix index e1c8bedf8..0234c4cf8 100644 --- a/tests/modules/home-environment/session-variables.nix +++ b/tests/modules/home-environment/session-variables.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, pkgs, ... }: let @@ -16,6 +16,7 @@ let export XDG_CONFIG_HOME="/home/hm-user/.config" export XDG_DATA_HOME="/home/hm-user/.local/share" export XDG_STATE_HOME="/home/hm-user/.local/state" + ''; darwinExpected = '' @@ -29,6 +30,7 @@ let export XDG_CONFIG_HOME="/home/hm-user/.config" export XDG_DATA_HOME="/home/hm-user/.local/share" export XDG_STATE_HOME="/home/hm-user/.local/state" + ''; expected = pkgs.writeText "expected" diff --git a/tests/modules/launchd/agents.nix b/tests/modules/launchd/agents.nix index ccf4f6e24..b47126ba9 100644 --- a/tests/modules/launchd/agents.nix +++ b/tests/modules/launchd/agents.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { launchd.agents."test-service" = { diff --git a/tests/modules/misc/editorconfig/editorconfig-simple-config.nix b/tests/modules/misc/editorconfig/editorconfig-simple-config.nix index ca0581e5f..58cdbee29 100644 --- a/tests/modules/misc/editorconfig/editorconfig-simple-config.nix +++ b/tests/modules/misc/editorconfig/editorconfig-simple-config.nix @@ -1,5 +1,3 @@ -{ ... }: - { editorconfig = { enable = true; diff --git a/tests/modules/misc/fontconfig/multiple-font-packages.nix b/tests/modules/misc/fontconfig/multiple-font-packages.nix index 3845b4ba4..c32bfb3ea 100644 --- a/tests/modules/misc/fontconfig/multiple-font-packages.nix +++ b/tests/modules/misc/fontconfig/multiple-font-packages.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ pkgs, ... }: { config = { home.packages = [ pkgs.comic-relief pkgs.unifont ]; diff --git a/tests/modules/misc/nix/example-registry.nix b/tests/modules/misc/nix/example-registry.nix index 99da470ef..70cb066b2 100644 --- a/tests/modules/misc/nix/example-registry.nix +++ b/tests/modules/misc/nix/example-registry.nix @@ -1,5 +1,3 @@ -{ ... }: - { nix = { registry = { diff --git a/tests/modules/misc/pam/session-variables.nix b/tests/modules/misc/pam/session-variables.nix index 4fbec4163..f2625da5f 100644 --- a/tests/modules/misc/pam/session-variables.nix +++ b/tests/modules/misc/pam/session-variables.nix @@ -1,8 +1,4 @@ -{ config, lib, ... }: - -with lib; - -{ +{ config, ... }: { config = { pam.sessionVariables = { V1 = "v1"; diff --git a/tests/modules/misc/specialisation/specialisation.nix b/tests/modules/misc/specialisation/specialisation.nix index a8d417d48..daea6e2c7 100644 --- a/tests/modules/misc/specialisation/specialisation.nix +++ b/tests/modules/misc/specialisation/specialisation.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { home.file.testfile.text = "not special"; specialisation.test.configuration = { diff --git a/tests/modules/misc/xdg/default-locations.nix b/tests/modules/misc/xdg/default-locations.nix index 1f6b36cc8..79f1f5321 100644 --- a/tests/modules/misc/xdg/default-locations.nix +++ b/tests/modules/misc/xdg/default-locations.nix @@ -1,11 +1,7 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, lib, ... }: { config = { # Test fallback behavior for stateVersion >= 20.09, which is pure. - xdg.enable = lib.mkForce false; + xdg.enable = false; home.stateVersion = "20.09"; xdg.configFile.test.text = "config"; diff --git a/tests/modules/misc/xdg/default.nix b/tests/modules/misc/xdg/default.nix index dde36f97e..13ebb7e10 100644 --- a/tests/modules/misc/xdg/default.nix +++ b/tests/modules/misc/xdg/default.nix @@ -1,13 +1,6 @@ { - xdg-mime-apps-basics = ./mime-apps-basics.nix; - xdg-system-dirs = ./system-dirs.nix; - xdg-desktop-entries = ./desktop-entries.nix; xdg-file-gen = ./file-gen.nix; xdg-default-locations = ./default-locations.nix; - xdg-user-dirs-null = ./user-dirs-null.nix; - xdg-portal = ./portal.nix; - xdg-mime = ./mime.nix; xdg-mime-disabled = ./mime-disabled.nix; - xdg-mime-package = ./mime-packages.nix; xdg-autostart = ./autostart.nix; } diff --git a/tests/modules/misc/xdg/desktop-entries.nix b/tests/modules/misc/xdg/desktop-entries.nix index 5f00029b6..9f52c550d 100644 --- a/tests/modules/misc/xdg/desktop-entries.nix +++ b/tests/modules/misc/xdg/desktop-entries.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ pkgs, ... }: { config = { xdg.desktopEntries = { full = { # full definition diff --git a/tests/modules/misc/xdg/file-gen.nix b/tests/modules/misc/xdg/file-gen.nix index 7514f414f..f06c6e520 100644 --- a/tests/modules/misc/xdg/file-gen.nix +++ b/tests/modules/misc/xdg/file-gen.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { config = { xdg.configHome = /. + "${config.home.homeDirectory}/.dummy-config"; xdg.dataHome = /. + "${config.home.homeDirectory}/.dummy-data"; diff --git a/tests/modules/misc/xdg/linux.nix b/tests/modules/misc/xdg/linux.nix new file mode 100644 index 000000000..b0a6bb043 --- /dev/null +++ b/tests/modules/misc/xdg/linux.nix @@ -0,0 +1,9 @@ +{ + xdg-mime-apps-basics = ./mime-apps-basics.nix; + xdg-system-dirs = ./system-dirs.nix; + xdg-desktop-entries = ./desktop-entries.nix; + xdg-user-dirs-null = ./user-dirs-null.nix; + xdg-portal = ./portal.nix; + xdg-mime = ./mime.nix; + xdg-mime-package = ./mime-packages.nix; +} diff --git a/tests/modules/misc/xdg/mime-apps-basics.nix b/tests/modules/misc/xdg/mime-apps-basics.nix index e181e8206..3688040e5 100644 --- a/tests/modules/misc/xdg/mime-apps-basics.nix +++ b/tests/modules/misc/xdg/mime-apps-basics.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { xdg.mimeApps = { diff --git a/tests/modules/misc/xdg/mime-disabled.nix b/tests/modules/misc/xdg/mime-disabled.nix index a3df63091..43885528b 100644 --- a/tests/modules/misc/xdg/mime-disabled.nix +++ b/tests/modules/misc/xdg/mime-disabled.nix @@ -1,4 +1,4 @@ -{ ... }: { +{ config = { xdg.mime.enable = false; nmt.script = '' diff --git a/tests/modules/misc/xsession/basic.nix b/tests/modules/misc/xsession/basic.nix index d6756291c..f212de19d 100644 --- a/tests/modules/misc/xsession/basic.nix +++ b/tests/modules/misc/xsession/basic.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { xsession = { diff --git a/tests/modules/misc/xsession/keyboard-without-layout.nix b/tests/modules/misc/xsession/keyboard-without-layout.nix index 90038cfd0..d49d60e02 100644 --- a/tests/modules/misc/xsession/keyboard-without-layout.nix +++ b/tests/modules/misc/xsession/keyboard-without-layout.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { home.stateVersion = "19.09"; diff --git a/tests/modules/programs/abook/no-settings.nix b/tests/modules/programs/abook/no-settings.nix index a8e5de78c..942c19e50 100644 --- a/tests/modules/programs/abook/no-settings.nix +++ b/tests/modules/programs/abook/no-settings.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.abook.enable = true; diff --git a/tests/modules/programs/abook/with-settings.nix b/tests/modules/programs/abook/with-settings.nix index 22703a172..a02c9d6fd 100644 --- a/tests/modules/programs/abook/with-settings.nix +++ b/tests/modules/programs/abook/with-settings.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.abook = { diff --git a/tests/modules/programs/aerc/assertion.nix b/tests/modules/programs/aerc/assertion.nix index dfdbe3f7d..b1523bbc0 100644 --- a/tests/modules/programs/aerc/assertion.nix +++ b/tests/modules/programs/aerc/assertion.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { test.asserts.assertions.expected = ['' diff --git a/tests/modules/programs/aerc/default.nix b/tests/modules/programs/aerc/default.nix index 9417a2197..80b7e9efc 100644 --- a/tests/modules/programs/aerc/default.nix +++ b/tests/modules/programs/aerc/default.nix @@ -2,4 +2,5 @@ aerc-noSettings = ./noSettings.nix; aerc-settings = ./settings.nix; aerc-assertion = ./assertion.nix; + aerc-oauth = ./oauth.nix; } diff --git a/tests/modules/programs/aerc/noSettings.nix b/tests/modules/programs/aerc/noSettings.nix index fc4cb2dbb..46d146bf9 100644 --- a/tests/modules/programs/aerc/noSettings.nix +++ b/tests/modules/programs/aerc/noSettings.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { nmt.script = let dir = "home-files/.config/aerc"; diff --git a/tests/modules/programs/aerc/oauth.expected b/tests/modules/programs/aerc/oauth.expected new file mode 100644 index 000000000..6824d1fed --- /dev/null +++ b/tests/modules/programs/aerc/oauth.expected @@ -0,0 +1,9 @@ +# Generated by Home Manager. + +[basic] +copy-to = Sent +default = Inbox +from = Annie X. Hacker +outgoing = smtp+xoauth2://anniex@smtp.office365.com:587?client_id=9e5f94bc-e8a4-4e73-b8be-63364c29d753&token_endpoint=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fv2.0%2Ftoken +postpone = Drafts +source = imaps+xoauth2://anniex@outlook.office365.com:993?client_id=9e5f94bc-e8a4-4e73-b8be-63364c29d753&token_endpoint=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fv2.0%2Ftoken diff --git a/tests/modules/programs/aerc/oauth.nix b/tests/modules/programs/aerc/oauth.nix new file mode 100644 index 000000000..e91d25203 --- /dev/null +++ b/tests/modules/programs/aerc/oauth.nix @@ -0,0 +1,39 @@ +{ config, pkgs, ... }: { + config = { + nmt.script = let + dir = if (pkgs.stdenv.isDarwin && !config.xdg.enable) then + "home-files/Library/Preferences/aerc" + else + "home-files/.config/aerc"; + in '' + assertFileContent ${dir}/accounts.conf ${./oauth.expected} + ''; + programs.aerc = { + enable = true; + extraConfig.general.unsafe-accounts-conf = true; + }; + + accounts.email.accounts = { + basic = { + realName = "Annie X. Hacker"; + userName = "anniex"; + address = "anniex@mail.invalid"; + primary = true; + flavor = "outlook.office365.com"; + + aerc = rec { + enable = true; + imapAuth = "xoauth2"; + smtpAuth = imapAuth; + imapOauth2Params = { + client_id = "9e5f94bc-e8a4-4e73-b8be-63364c29d753"; + token_endpoint = + "https://login.microsoftonline.com/common/oauth2/v2.0/token"; + }; + smtpOauth2Params = imapOauth2Params; + }; + }; + }; + }; +} + diff --git a/tests/modules/programs/aerc/settings.nix b/tests/modules/programs/aerc/settings.nix index 8d59f1e6c..306930985 100644 --- a/tests/modules/programs/aerc/settings.nix +++ b/tests/modules/programs/aerc/settings.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, pkgs, ... }: { config = { nmt.script = let dir = if (pkgs.stdenv.isDarwin && !config.xdg.enable) then diff --git a/tests/modules/programs/atuin/example-settings.nix b/tests/modules/programs/atuin/example-settings.nix index dab1b9e3a..c23b84e3e 100644 --- a/tests/modules/programs/atuin/example-settings.nix +++ b/tests/modules/programs/atuin/example-settings.nix @@ -1,5 +1,3 @@ -{ ... }: - { programs.atuin = { enable = true; diff --git a/tests/modules/programs/bash/bash-history-control-with-file.nix b/tests/modules/programs/bash/bash-history-control-with-file.nix index 449da8860..d3193232a 100644 --- a/tests/modules/programs/bash/bash-history-control-with-file.nix +++ b/tests/modules/programs/bash/bash-history-control-with-file.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.bash = { diff --git a/tests/modules/programs/bottom/empty-settings.nix b/tests/modules/programs/bottom/empty-settings.nix index 71799c831..3c5c8b72a 100644 --- a/tests/modules/programs/bottom/empty-settings.nix +++ b/tests/modules/programs/bottom/empty-settings.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { config = { programs.bottom = { enable = true; diff --git a/tests/modules/programs/bottom/example-settings.nix b/tests/modules/programs/bottom/example-settings.nix index a0ed11085..918969b1d 100644 --- a/tests/modules/programs/bottom/example-settings.nix +++ b/tests/modules/programs/bottom/example-settings.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { config = { programs.bottom = { enable = true; diff --git a/tests/modules/programs/boxxy/empty-settings.nix b/tests/modules/programs/boxxy/empty-settings.nix index 133d670f5..61692a237 100644 --- a/tests/modules/programs/boxxy/empty-settings.nix +++ b/tests/modules/programs/boxxy/empty-settings.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.boxxy.enable = true; diff --git a/tests/modules/programs/boxxy/example-settings.nix b/tests/modules/programs/boxxy/example-settings.nix index 6f10a56c3..46003a0e7 100644 --- a/tests/modules/programs/boxxy/example-settings.nix +++ b/tests/modules/programs/boxxy/example-settings.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.boxxy.enable = true; diff --git a/tests/modules/programs/carapace/fish.nix b/tests/modules/programs/carapace/fish.nix index f0a281d38..b83136c6c 100644 --- a/tests/modules/programs/carapace/fish.nix +++ b/tests/modules/programs/carapace/fish.nix @@ -8,13 +8,17 @@ lib.mkIf config.test.enableBig { nixpkgs.overlays = [ (self: super: { inherit (realPkgs) carapace; }) ]; - nmt.script = '' + nmt.script = let + needsCompletionOverrides = lib.versionOlder realPkgs.fish.version "4.0.0"; + in '' assertFileExists home-files/.config/fish/config.fish assertFileRegex home-files/.config/fish/config.fish \ '/nix/store/.*carapace.*/bin/carapace _carapace fish \| source' - - # Check whether completions are overridden. + '' + (lib.optionalString needsCompletionOverrides '' + # Check whether completions are overridden, necessary for fish < 4.0 assertFileExists home-files/.config/fish/completions/git.fish assertFileContent home-files/.config/fish/completions/git.fish /dev/null - ''; + '') + (lib.optionalString (!needsCompletionOverrides) '' + assertPathNotExists home-files/.config/fish/completions + ''); } diff --git a/tests/modules/programs/dircolors/default.nix b/tests/modules/programs/dircolors/default.nix index a82e2b859..39d44858f 100644 --- a/tests/modules/programs/dircolors/default.nix +++ b/tests/modules/programs/dircolors/default.nix @@ -1 +1,4 @@ -{ dircolors-settings = ./settings.nix; } +{ + dircolors-settings = ./settings.nix; + dircolors-xdg-config-settings = ./xdg-config-settings.nix; +} diff --git a/tests/modules/programs/dircolors/settings.nix b/tests/modules/programs/dircolors/settings.nix index 9ca676ef9..f2802aaa0 100644 --- a/tests/modules/programs/dircolors/settings.nix +++ b/tests/modules/programs/dircolors/settings.nix @@ -1,9 +1,7 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ pkgs, ... }: { config = { + programs.zsh.enable = true; + programs.dircolors = { enable = true; @@ -22,6 +20,11 @@ with lib; assertFileContent \ home-files/.dir_colors \ ${./settings-expected.conf} + + + assertFileRegex \ + home-files/.zshrc \ + "eval \$(${pkgs.coreutils}/bin/dircolors -b ~/.dir_colors)" ''; }; } diff --git a/tests/modules/programs/dircolors/xdg-config-settings.nix b/tests/modules/programs/dircolors/xdg-config-settings.nix new file mode 100644 index 000000000..dd48dd8c1 --- /dev/null +++ b/tests/modules/programs/dircolors/xdg-config-settings.nix @@ -0,0 +1,31 @@ +{ config, pkgs, ... }: { + config = { + home.preferXdgDirectories = true; + + programs.zsh.enable = true; + + programs.dircolors = { + enable = true; + + settings = { + OTHER_WRITABLE = "30;46"; + ".sh" = "01;32"; + ".csh" = "01;32"; + }; + + extraConfig = '' + # Extra dircolors configuration. + ''; + }; + + nmt.script = '' + assertFileContent \ + home-files/.config/dir_colors \ + ${./settings-expected.conf} + + assertFileRegex \ + home-files/.zshrc \ + "eval \$(${pkgs.coreutils}/bin/dircolors -b ${config.xdg.configHome}/dir_colors)" + ''; + }; +} diff --git a/tests/modules/programs/distrobox/default.nix b/tests/modules/programs/distrobox/default.nix new file mode 100644 index 000000000..2dbe7e46b --- /dev/null +++ b/tests/modules/programs/distrobox/default.nix @@ -0,0 +1 @@ +{ distrobox-example-config = ./example-config.nix; } diff --git a/tests/modules/programs/distrobox/example-config.ini b/tests/modules/programs/distrobox/example-config.ini new file mode 100644 index 000000000..31ce6682c --- /dev/null +++ b/tests/modules/programs/distrobox/example-config.ini @@ -0,0 +1,20 @@ +[common-debian] +additional_packages=git +entry=true +image=debian:13 +init_hooks=ln -sf /usr/bin/distrobox-host-exec /usr/local/bin/docker +init_hooks=ln -sf /usr/bin/distrobox-host-exec /usr/local/bin/docker-compose + +[office] +additional_packages=libreoffice onlyoffice +clone=common-debian +entry=true + +[python-project] +additional_packages=python3 git +image=fedora:40 +init_hooks=pip3 install numpy pandas torch torchvision + +[random-things] +clone=common-debian +entry=false diff --git a/tests/modules/programs/distrobox/example-config.nix b/tests/modules/programs/distrobox/example-config.nix new file mode 100644 index 000000000..6046d0f7f --- /dev/null +++ b/tests/modules/programs/distrobox/example-config.nix @@ -0,0 +1,41 @@ +{ + programs.distrobox = { + enable = true; + containers = { + + python-project = { + image = "fedora:40"; + additional_packages = "python3 git"; + init_hooks = "pip3 install numpy pandas torch torchvision"; + }; + + common-debian = { + image = "debian:13"; + entry = true; + additional_packages = "git"; + init_hooks = [ + "ln -sf /usr/bin/distrobox-host-exec /usr/local/bin/docker" + "ln -sf /usr/bin/distrobox-host-exec /usr/local/bin/docker-compose" + ]; + }; + + office = { + clone = "common-debian"; + additional_packages = "libreoffice onlyoffice"; + entry = true; + }; + + random-things = { + clone = "common-debian"; + entry = false; + }; + + }; + }; + + nmt.script = '' + assertFileExists home-files/.config/distrobox/containers.ini + assertFileContent home-files/.config/distrobox/containers.ini \ + ${./example-config.ini} + ''; +} diff --git a/tests/modules/programs/earthly/default.nix b/tests/modules/programs/earthly/default.nix new file mode 100644 index 000000000..5606289c1 --- /dev/null +++ b/tests/modules/programs/earthly/default.nix @@ -0,0 +1 @@ +{ earthly-settings = ./earthly-settings.nix; } diff --git a/tests/modules/programs/earthly/earthly-settings.nix b/tests/modules/programs/earthly/earthly-settings.nix new file mode 100644 index 000000000..1710e5a4c --- /dev/null +++ b/tests/modules/programs/earthly/earthly-settings.nix @@ -0,0 +1,21 @@ +{ + programs.earthly = { + enable = true; + + settings = { + global.disable_analytics = true; + + git."github.com" = { + auth = "ssh"; + user = "username"; + }; + }; + }; + + test.stubs.earthly = { }; + + nmt.script = '' + assertFileExists home-files/.earthly/config.yml + assertFileContent home-files/.earthly/config.yml ${./earthly-settings.yml} + ''; +} diff --git a/tests/modules/programs/earthly/earthly-settings.yml b/tests/modules/programs/earthly/earthly-settings.yml new file mode 100644 index 000000000..182f011b2 --- /dev/null +++ b/tests/modules/programs/earthly/earthly-settings.yml @@ -0,0 +1,6 @@ +git: + github.com: + auth: ssh + user: username +global: + disable_analytics: true diff --git a/tests/modules/programs/eww/basic-config.nix b/tests/modules/programs/eww/basic-config.nix index cc207e100..30059d4f1 100644 --- a/tests/modules/programs/eww/basic-config.nix +++ b/tests/modules/programs/eww/basic-config.nix @@ -1,4 +1,4 @@ -{ ... }: { +{ config = { programs.eww = { enable = true; diff --git a/tests/modules/programs/eww/null-config.nix b/tests/modules/programs/eww/null-config.nix index 28cd6fc68..0ae1b903b 100644 --- a/tests/modules/programs/eww/null-config.nix +++ b/tests/modules/programs/eww/null-config.nix @@ -1,4 +1,4 @@ -{ ... }: { +{ config = { programs.eww = { enable = true; }; diff --git a/tests/modules/programs/firefox/common.nix b/tests/modules/programs/firefox/common.nix index c92db1e4c..f086702d1 100644 --- a/tests/modules/programs/firefox/common.nix +++ b/tests/modules/programs/firefox/common.nix @@ -1,15 +1,18 @@ name: builtins.mapAttrs (test: module: import module [ "programs" name ]) { "${name}-deprecated-native-messenger" = ./deprecated-native-messenger.nix; + "${name}-null-package" = ./null-package.nix; "${name}-final-package" = ./final-package.nix; "${name}-policies" = ./policies.nix; "${name}-profiles-bookmarks" = ./profiles/bookmarks; + "${name}-profiles-bookmarks-attrset" = ./profiles/bookmarks/attrset.nix; "${name}-profiles-containers" = ./profiles/containers; "${name}-profiles-containers-duplicate-ids" = ./profiles/containers/duplicate-ids.nix; "${name}-profiles-containers-id-out-of-range" = ./profiles/containers/id-out-of-range.nix; "${name}-profiles-duplicate-ids" = ./profiles/duplicate-ids.nix; + "${name}-profiles-extensions" = ./profiles/extensions; "${name}-profiles-overwrite" = ./profiles/overwrite; "${name}-profiles-search" = ./profiles/search; "${name}-profiles-settings" = ./profiles/settings; diff --git a/tests/modules/programs/firefox/default.nix b/tests/modules/programs/firefox/default.nix new file mode 100644 index 000000000..4e7b93c69 --- /dev/null +++ b/tests/modules/programs/firefox/default.nix @@ -0,0 +1 @@ +{ "firefox-multiple-derivatives" = ./multiple-derivatives.nix; } diff --git a/tests/modules/programs/firefox/deprecated-native-messenger.nix b/tests/modules/programs/firefox/deprecated-native-messenger.nix index 87423aba3..53309cee4 100644 --- a/tests/modules/programs/firefox/deprecated-native-messenger.nix +++ b/tests/modules/programs/firefox/deprecated-native-messenger.nix @@ -1,18 +1,13 @@ modulePath: { config, lib, ... }: - -with lib; - let - - moduleName = concatStringsSep "." modulePath; + moduleName = lib.concatStringsSep "." modulePath; firefoxMockOverlay = import ./setup-firefox-mock-overlay.nix modulePath; - in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig (setAttrByPath modulePath { + config = lib.mkIf config.test.enableBig (lib.setAttrByPath modulePath { enable = true; enableGnomeExtensions = true; } // { diff --git a/tests/modules/programs/firefox/librewolf.nix b/tests/modules/programs/firefox/librewolf.nix new file mode 100644 index 000000000..3a77e0f1d --- /dev/null +++ b/tests/modules/programs/firefox/librewolf.nix @@ -0,0 +1 @@ +import ./common.nix "librewolf" diff --git a/tests/modules/programs/firefox/multiple-derivatives.nix b/tests/modules/programs/firefox/multiple-derivatives.nix new file mode 100644 index 000000000..12a35de70 --- /dev/null +++ b/tests/modules/programs/firefox/multiple-derivatives.nix @@ -0,0 +1,16 @@ +{ config, lib, ... }: + +lib.mkIf config.test.enableBig { + programs.firefox = { + enable = true; + package = null; + }; + programs.floorp = { + enable = true; + package = null; + }; + programs.librewolf = { + enable = true; + package = null; + }; +} diff --git a/tests/modules/programs/firefox/null-package.nix b/tests/modules/programs/firefox/null-package.nix new file mode 100644 index 000000000..e5d1516dc --- /dev/null +++ b/tests/modules/programs/firefox/null-package.nix @@ -0,0 +1,10 @@ +modulePath: +{ config, lib, ... }: + +lib.mkIf config.test.enableBig (lib.setAttrByPath modulePath { enable = true; } + // { + programs.firefox = { + enable = true; + package = null; + }; + }) diff --git a/tests/modules/programs/firefox/policies.nix b/tests/modules/programs/firefox/policies.nix index 5cda1406a..4cf761a53 100644 --- a/tests/modules/programs/firefox/policies.nix +++ b/tests/modules/programs/firefox/policies.nix @@ -1,20 +1,15 @@ modulePath: { config, lib, pkgs, ... }: - -with lib; - let - - cfg = getAttrFromPath modulePath config; + cfg = lib.getAttrFromPath modulePath config; firefoxMockOverlay = import ./setup-firefox-mock-overlay.nix modulePath; - in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig ({ + config = lib.mkIf config.test.enableBig ({ home.stateVersion = "23.05"; - } // setAttrByPath modulePath { + } // lib.setAttrByPath modulePath { enable = true; policies = { BlockAboutConfig = true; }; package = pkgs.${cfg.wrappedPackageName}.override { diff --git a/tests/modules/programs/firefox/profiles/bookmarks/attrset.nix b/tests/modules/programs/firefox/profiles/bookmarks/attrset.nix new file mode 100644 index 000000000..c4e3c4362 --- /dev/null +++ b/tests/modules/programs/firefox/profiles/bookmarks/attrset.nix @@ -0,0 +1,82 @@ +modulePath: +{ config, lib, ... }: + +let + + cfg = lib.getAttrFromPath modulePath config; + + firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath; + +in { + imports = [ firefoxMockOverlay ]; + + config = lib.mkIf config.test.enableBig (lib.setAttrByPath modulePath { + enable = true; + profiles.bookmarks = { + settings = { "general.smoothScroll" = false; }; + bookmarks = { + home-manager = { + toolbar = true; + bookmarks = [{ + name = "Home Manager"; + url = "https://wiki.nixos.org/wiki/Home_Manager"; + }]; + }; + wikipedia = { + name = "wikipedia"; + tags = [ "wiki" ]; + keyword = "wiki"; + url = "https://en.wikipedia.org/wiki/Special:Search?search=%s&go=Go"; + }; + kernel-org = { + name = "kernel.org"; + url = "https://www.kernel.org"; + }; + nix-sites = { + name = "Nix sites"; + bookmarks = [ + { + name = "homepage"; + url = "https://nixos.org/"; + } + { + name = "wiki"; + tags = [ "wiki" "nix" ]; + url = "https://wiki.nixos.org/"; + } + { + name = "Nix sites"; + bookmarks = [ + { + name = "homepage"; + url = "https://nixos.org/"; + } + { + name = "wiki"; + url = "https://wiki.nixos.org/"; + } + ]; + } + ]; + }; + }; + }; + } // { + nmt.script = '' + bookmarksUserJs=$(normalizeStorePaths \ + home-files/${cfg.configPath}/bookmarks/user.js) + + assertFileContent \ + $bookmarksUserJs \ + ${./expected-bookmarks-user.js} + + bookmarksFile="$(sed -n \ + '/browser.bookmarks.file/ {s|^.*\(/nix/store[^"]*\).*|\1|;p}' \ + $TESTED/home-files/${cfg.configPath}/bookmarks/user.js)" + + assertFileContent \ + $bookmarksFile \ + ${./expected-bookmarks.html} + ''; + }); +} diff --git a/tests/modules/programs/firefox/profiles/bookmarks/default.nix b/tests/modules/programs/firefox/profiles/bookmarks/default.nix index dfbcfbd92..635b760e1 100644 --- a/tests/modules/programs/firefox/profiles/bookmarks/default.nix +++ b/tests/modules/programs/firefox/profiles/bookmarks/default.nix @@ -1,73 +1,69 @@ modulePath: { config, lib, pkgs, ... }: -with lib; - let - cfg = getAttrFromPath modulePath config; + cfg = lib.getAttrFromPath modulePath config; firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath; - withName = path: - pkgs.substituteAll { - src = path; - name = cfg.wrappedPackageName; - }; - in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig (setAttrByPath modulePath { + config = lib.mkIf config.test.enableBig (lib.setAttrByPath modulePath { enable = true; profiles.bookmarks = { settings = { "general.smoothScroll" = false; }; - bookmarks = [ - { - toolbar = true; - bookmarks = [{ - name = "Home Manager"; - url = "https://wiki.nixos.org/wiki/Home_Manager"; - }]; - } - { - name = "wikipedia"; - tags = [ "wiki" ]; - keyword = "wiki"; - url = "https://en.wikipedia.org/wiki/Special:Search?search=%s&go=Go"; - } - { - name = "kernel.org"; - url = "https://www.kernel.org"; - } - { - name = "Nix sites"; - bookmarks = [ - { - name = "homepage"; - url = "https://nixos.org/"; - } - { - name = "wiki"; - tags = [ "wiki" "nix" ]; - url = "https://wiki.nixos.org/"; - } - { - name = "Nix sites"; - bookmarks = [ - { - name = "homepage"; - url = "https://nixos.org/"; - } - { - name = "wiki"; - url = "https://wiki.nixos.org/"; - } - ]; - } - ]; - } - ]; + bookmarks = { + force = true; + settings = [ + { + toolbar = true; + bookmarks = [{ + name = "Home Manager"; + url = "https://wiki.nixos.org/wiki/Home_Manager"; + }]; + } + { + name = "kernel.org"; + url = "https://www.kernel.org"; + } + { + name = "Nix sites"; + bookmarks = [ + { + name = "homepage"; + url = "https://nixos.org/"; + } + { + name = "wiki"; + tags = [ "wiki" "nix" ]; + url = "https://wiki.nixos.org/"; + } + { + name = "Nix sites"; + bookmarks = [ + { + name = "homepage"; + url = "https://nixos.org/"; + } + { + name = "wiki"; + url = "https://wiki.nixos.org/"; + } + ]; + } + ]; + } + { + name = "wikipedia"; + tags = [ "wiki" ]; + keyword = "wiki"; + url = + "https://en.wikipedia.org/wiki/Special:Search?search=%s&go=Go"; + } + ]; + }; }; } // { nmt.script = '' @@ -76,7 +72,7 @@ in { assertFileContent \ $bookmarksUserJs \ - ${withName ./expected-bookmarks-user.js} + ${./expected-bookmarks-user.js} bookmarksFile="$(sed -n \ '/browser.bookmarks.file/ {s|^.*\(/nix/store[^"]*\).*|\1|;p}' \ diff --git a/tests/modules/programs/firefox/profiles/bookmarks/expected-bookmarks-user.js b/tests/modules/programs/firefox/profiles/bookmarks/expected-bookmarks-user.js index d36dccfdf..fe8e8b2eb 100644 --- a/tests/modules/programs/firefox/profiles/bookmarks/expected-bookmarks-user.js +++ b/tests/modules/programs/firefox/profiles/bookmarks/expected-bookmarks-user.js @@ -2,7 +2,7 @@ -user_pref("browser.bookmarks.file", "/nix/store/00000000000000000000000000000000-@name@-bookmarks.html"); +user_pref("browser.bookmarks.file", "/nix/store/00000000000000000000000000000000-bookmarks.html"); user_pref("browser.places.importBookmarksHTML", true); user_pref("general.smoothScroll", false); diff --git a/tests/modules/programs/firefox/profiles/bookmarks/expected-bookmarks.html b/tests/modules/programs/firefox/profiles/bookmarks/expected-bookmarks.html index 93bc195fb..4f22e86cc 100644 --- a/tests/modules/programs/firefox/profiles/bookmarks/expected-bookmarks.html +++ b/tests/modules/programs/firefox/profiles/bookmarks/expected-bookmarks.html @@ -10,7 +10,6 @@

Home Manager

-

wikipedia
kernel.org

Nix sites

@@ -22,4 +21,5 @@

wiki

+

wikipedia diff --git a/tests/modules/programs/firefox/profiles/containers/default.nix b/tests/modules/programs/firefox/profiles/containers/default.nix index 6a0d9e93f..e0e917773 100644 --- a/tests/modules/programs/firefox/profiles/containers/default.nix +++ b/tests/modules/programs/firefox/profiles/containers/default.nix @@ -1,18 +1,15 @@ modulePath: -{ config, lib, pkgs, ... }: - -with lib; - +{ config, lib, ... }: let - cfg = getAttrFromPath modulePath config; + cfg = lib.getAttrFromPath modulePath config; firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath; in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig (setAttrByPath modulePath { + config = lib.mkIf config.test.enableBig (lib.setAttrByPath modulePath { enable = true; profiles.containers = { containers = { diff --git a/tests/modules/programs/firefox/profiles/containers/duplicate-ids.nix b/tests/modules/programs/firefox/profiles/containers/duplicate-ids.nix index a60522165..0c9d2e666 100644 --- a/tests/modules/programs/firefox/profiles/containers/duplicate-ids.nix +++ b/tests/modules/programs/firefox/profiles/containers/duplicate-ids.nix @@ -1,22 +1,20 @@ modulePath: { config, lib, ... }: -with lib; - let - cfg = getAttrFromPath modulePath config; + cfg = lib.getAttrFromPath modulePath config; firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath; in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig ({ + config = lib.mkIf config.test.enableBig ({ test.asserts.assertions.expected = ['' Must not have a ${cfg.name} container with an existing ID but - ID 9 is used by dangerous, shopping'']; - } // setAttrByPath modulePath { + } // lib.setAttrByPath modulePath { enable = true; profiles = { diff --git a/tests/modules/programs/firefox/profiles/containers/id-out-of-range.nix b/tests/modules/programs/firefox/profiles/containers/id-out-of-range.nix index f39666723..d2c273f9b 100644 --- a/tests/modules/programs/firefox/profiles/containers/id-out-of-range.nix +++ b/tests/modules/programs/firefox/profiles/containers/id-out-of-range.nix @@ -1,8 +1,6 @@ modulePath: { config, lib, ... }: -with lib; - let firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath; @@ -10,10 +8,10 @@ let in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig ({ + config = lib.mkIf config.test.enableBig ({ test.asserts.assertions.expected = [ "Container id must be smaller than 4294967294 (2^32 - 2)" ]; - } // setAttrByPath modulePath { + } // lib.setAttrByPath modulePath { enable = true; profiles.my-profile = { diff --git a/tests/modules/programs/firefox/profiles/duplicate-ids.nix b/tests/modules/programs/firefox/profiles/duplicate-ids.nix index dc5557b47..255715f4a 100644 --- a/tests/modules/programs/firefox/profiles/duplicate-ids.nix +++ b/tests/modules/programs/firefox/profiles/duplicate-ids.nix @@ -1,22 +1,20 @@ modulePath: { config, lib, ... }: -with lib; - let - cfg = getAttrFromPath modulePath config; + cfg = lib.getAttrFromPath modulePath config; firefoxMockOverlay = import ../setup-firefox-mock-overlay.nix modulePath; in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig ({ + config = lib.mkIf config.test.enableBig ({ test.asserts.assertions.expected = ['' Must not have a ${cfg.name} profile with an existing ID but - ID 1 is used by first, second'']; - } // setAttrByPath modulePath { + } // lib.setAttrByPath modulePath { enable = true; profiles = { diff --git a/tests/modules/programs/firefox/profiles/extensions/default.nix b/tests/modules/programs/firefox/profiles/extensions/default.nix index 577518390..77fbe33b0 100644 --- a/tests/modules/programs/firefox/profiles/extensions/default.nix +++ b/tests/modules/programs/firefox/profiles/extensions/default.nix @@ -1,30 +1,35 @@ modulePath: -{ config, lib, pkgs, ... }: -with lib; +{ config, lib, ... }: + let - cfg = getAttrFromPath modulePath config; + cfg = lib.getAttrFromPath modulePath config; firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath; in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig (setAttrByPath modulePath { + config = lib.mkIf config.test.enableBig (lib.setAttrByPath modulePath { enable = true; profiles.extensions = { - extensions.settings."uBlock0@raymondhill.net".settings = { - selectedFilterLists = [ - "ublock-filters" - "ublock-badware" - "ublock-privacy" - "ublock-unbreak" - "ublock-quick-fixes" - ]; + extensions = { + force = true; + settings = { + "uBlock0@raymondhill.net".settings = { + selectedFilterLists = [ + "ublock-filters" + "ublock-badware" + "ublock-privacy" + "ublock-unbreak" + "ublock-quick-fixes" + ]; + }; + }; }; }; } // { nmt.script = '' assertFileContent \ - home-files/${cfg.configPath}/extensions/uBlock0@raymondhill.net/storage.js \ + home-files/${cfg.configPath}/extensions/browser-extension-data/uBlock0@raymondhill.net/storage.js \ ${./expected-storage.js} ''; }); diff --git a/tests/modules/programs/firefox/profiles/extensions/expected-storage.js b/tests/modules/programs/firefox/profiles/extensions/expected-storage.js index 66c2a8d0f..225234411 100644 --- a/tests/modules/programs/firefox/profiles/extensions/expected-storage.js +++ b/tests/modules/programs/firefox/profiles/extensions/expected-storage.js @@ -1 +1 @@ -{"selectedFilterLists":["ublock-filters","ublock-badware","ublock-privacy","ublock-unbreak","ublock-quick-fixes"]} +{"selectedFilterLists":["ublock-filters","ublock-badware","ublock-privacy","ublock-unbreak","ublock-quick-fixes"]} \ No newline at end of file diff --git a/tests/modules/programs/firefox/profiles/overwrite/default.nix b/tests/modules/programs/firefox/profiles/overwrite/default.nix index a0881032a..02ec789d6 100644 --- a/tests/modules/programs/firefox/profiles/overwrite/default.nix +++ b/tests/modules/programs/firefox/profiles/overwrite/default.nix @@ -1,18 +1,16 @@ modulePath: -{ config, lib, pkgs, ... }: - -with lib; +{ config, lib, ... }: let - cfg = getAttrFromPath modulePath config; + cfg = lib.getAttrFromPath modulePath config; firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath; in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig (setAttrByPath modulePath { + config = lib.mkIf config.test.enableBig (lib.setAttrByPath modulePath { enable = true; profiles = { basic.isDefault = true; diff --git a/tests/modules/programs/firefox/profiles/search/default.nix b/tests/modules/programs/firefox/profiles/search/default.nix index 76acfcd3a..76baf1230 100644 --- a/tests/modules/programs/firefox/profiles/search/default.nix +++ b/tests/modules/programs/firefox/profiles/search/default.nix @@ -1,11 +1,9 @@ modulePath: { config, lib, pkgs, ... }: -with lib; - let - cfg = getAttrFromPath modulePath config; + cfg = lib.getAttrFromPath modulePath config; firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath; @@ -18,11 +16,89 @@ let in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig (setAttrByPath modulePath { + config = lib.mkIf config.test.enableBig (lib.setAttrByPath modulePath { enable = true; profiles = { search = { id = 0; + search = { + force = true; + default = "google"; + privateDefault = "ddg"; + order = [ "nix-packages" "nixos-wiki" ]; + engines = { + nix-packages = { + name = "Nix Packages"; + + urls = [{ + template = "https://search.nixos.org/packages"; + params = [ + { + name = "type"; + value = "packages"; + } + { + name = "query"; + value = "{searchTerms}"; + } + ]; + }]; + + icon = + "/run/current-system/sw/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + + definedAliases = [ "@np" ]; + }; + + nixos-wiki = { + name = "NixOS Wiki"; + + urls = [{ + template = + "https://wiki.nixos.org/w/index.php?search={searchTerms}"; + }]; + + iconMapObj."16" = "https://wiki.nixos.org/favicon.ico"; + definedAliases = [ "@nw" ]; + }; + + bing.metaData.hidden = true; + google.metaData.alias = "@g"; + }; + }; + }; + + searchWithoutDefault = { + id = 1; + search = { + force = true; + order = [ "google" "nix-packages" ]; + engines = { + nix-packages = { + name = "Nix Packages"; + + urls = [{ + template = "https://search.nixos.org/packages"; + params = [ + { + name = "type"; + value = "packages"; + } + { + name = "query"; + value = "{searchTerms}"; + } + ]; + }]; + + definedAliases = [ "@np" ]; + }; + }; + }; + }; + + migrateSearchV7 = { + id = 2; search = { force = true; default = "Google"; @@ -55,7 +131,7 @@ in { template = "https://wiki.nixos.org/index.php?search={searchTerms}"; }]; - iconUpdateURL = "https://wiki.nixos.org/favicon.png"; + iconUpdateURL = "https://wiki.nixos.org/favicon.ico"; updateInterval = 24 * 60 * 60 * 1000; definedAliases = [ "@nw" ]; }; @@ -66,13 +142,36 @@ in { }; }; - searchWithoutDefault = { - id = 1; + migrateIconsV11 = { + id = 3; search = { force = true; - order = [ "Google" "Nix Packages" ]; engines = { - "Nix Packages" = { + nixos-wiki = { + name = "NixOS Wiki"; + + urls = [{ + template = + "https://wiki.nixos.org/w/index.php?search={searchTerms}"; + }]; + + iconMapObj."{\"width\":16,\"height\":16}" = + "https://wiki.nixos.org/favicon.ico"; + + definedAliases = [ "@nw" ]; + }; + }; + }; + }; + + migrateIconsV12 = { + id = 4; + search = { + force = true; + engines = { + nix-packages = { + name = "Nix Packages"; + urls = [{ template = "https://search.nixos.org/packages"; params = [ @@ -87,6 +186,8 @@ in { ]; }]; + iconURL = "https://search.nixos.org/favicon.ico"; + iconUpdateURL = "https://search.nixos.org/favicon.ico"; definedAliases = [ "@np" ]; }; }; @@ -108,8 +209,8 @@ in { f end; walk(if type == "object" then - if has("hash") then .hash = null else . end | - if has("privateHash") then .privateHash = null else . end + if has("defaultEngineIdHash") then .defaultEngineIdHash = "@hash@" else . end | + if has("privateDefaultEngineIdHash") then .privateDefaultEngineIdHash = "@privateHash@" else . end else . end)' ''; @@ -133,6 +234,18 @@ in { assertFirefoxSearchContent \ home-files/${cfg.configPath}/searchWithoutDefault/search.json.mozlz4 \ ${withName ./expected-search-without-default.json} + + assertFirefoxSearchContent \ + home-files/${cfg.configPath}/migrateSearchV7/search.json.mozlz4 \ + ${withName ./expected-migrate-search-v7.json} + + assertFirefoxSearchContent \ + home-files/${cfg.configPath}/migrateIconsV11/search.json.mozlz4 \ + ${withName ./expected-migrate-icons-v11.json} + + assertFirefoxSearchContent \ + home-files/${cfg.configPath}/migrateIconsV12/search.json.mozlz4 \ + ${withName ./expected-migrate-icons-v12.json} ''; }); } diff --git a/tests/modules/programs/firefox/profiles/search/expected-migrate-icons-v11.json b/tests/modules/programs/firefox/profiles/search/expected-migrate-icons-v11.json new file mode 100644 index 000000000..d9534b44e --- /dev/null +++ b/tests/modules/programs/firefox/profiles/search/expected-migrate-icons-v11.json @@ -0,0 +1,26 @@ +{ + "engines": [ + { + "_definedAliases": [ + "@nw" + ], + "_iconMapObj": { + "16": "https://wiki.nixos.org/favicon.ico" + }, + "_isAppProvided": false, + "_loadPath": "[home-manager]/programs.@name@.profiles.migrateIconsV11.search.engines.nixos-wiki", + "_metaData": {}, + "_name": "NixOS Wiki", + "_urls": [ + { + "template": "https://wiki.nixos.org/w/index.php?search={searchTerms}" + } + ], + "id": "nixos-wiki" + } + ], + "metaData": { + "useSavedOrder": false + }, + "version": 12 +} diff --git a/tests/modules/programs/firefox/profiles/search/expected-migrate-icons-v12.json b/tests/modules/programs/firefox/profiles/search/expected-migrate-icons-v12.json new file mode 100644 index 000000000..bc863e5af --- /dev/null +++ b/tests/modules/programs/firefox/profiles/search/expected-migrate-icons-v12.json @@ -0,0 +1,36 @@ +{ + "engines": [ + { + "_definedAliases": [ + "@np" + ], + "_iconMapObj": { + "16": "https://search.nixos.org/favicon.ico" + }, + "_isAppProvided": false, + "_loadPath": "[home-manager]/programs.@name@.profiles.migrateIconsV12.search.engines.nix-packages", + "_metaData": {}, + "_name": "Nix Packages", + "_urls": [ + { + "params": [ + { + "name": "type", + "value": "packages" + }, + { + "name": "query", + "value": "{searchTerms}" + } + ], + "template": "https://search.nixos.org/packages" + } + ], + "id": "nix-packages" + } + ], + "metaData": { + "useSavedOrder": false + }, + "version": 12 +} diff --git a/tests/modules/programs/firefox/profiles/search/expected-migrate-icons.json b/tests/modules/programs/firefox/profiles/search/expected-migrate-icons.json new file mode 100644 index 000000000..0d03f947c --- /dev/null +++ b/tests/modules/programs/firefox/profiles/search/expected-migrate-icons.json @@ -0,0 +1,54 @@ +{ + "engines": [ + { + "_definedAliases": [ + "@np" + ], + "_iconMapObj": { + "16": "https://search.nixos.org/favicon.ico" + }, + "_isAppProvided": false, + "_loadPath": "[home-manager]/programs.@name@.profiles.migrateIcons.search.engines.nix-packages", + "_metaData": {}, + "_name": "Nix Packages", + "_urls": [ + { + "params": [ + { + "name": "type", + "value": "packages" + }, + { + "name": "query", + "value": "{searchTerms}" + } + ], + "template": "https://search.nixos.org/packages" + } + ], + "id": "nix-packages" + }, + { + "_definedAliases": [ + "@nw" + ], + "_iconMapObj": { + "16": "https://wiki.nixos.org/favicon.ico" + }, + "_isAppProvided": false, + "_loadPath": "[home-manager]/programs.@name@.profiles.migrateIcons.search.engines.nixos-wiki", + "_metaData": {}, + "_name": "NixOS Wiki", + "_urls": [ + { + "template": "https://wiki.nixos.org/w/index.php?search={searchTerms}" + } + ], + "id": "nixos-wiki" + } + ], + "metaData": { + "useSavedOrder": false + }, + "version": 12 +} diff --git a/tests/modules/programs/firefox/profiles/search/expected-migrate-search-v7.json b/tests/modules/programs/firefox/profiles/search/expected-migrate-search-v7.json new file mode 100644 index 000000000..bdd1ca1c4 --- /dev/null +++ b/tests/modules/programs/firefox/profiles/search/expected-migrate-search-v7.json @@ -0,0 +1,82 @@ +{ + "engines": [ + { + "_definedAliases": [ + "@np" + ], + "_iconMapObj": { + "16": "file:///run/current-system/sw/share/icons/hicolor/scalable/apps/nix-snowflake.svg" + }, + "_isAppProvided": false, + "_loadPath": "[home-manager]/programs.@name@.profiles.migrateSearchV7.search.engines.\"Nix Packages\"", + "_metaData": { + "order": 1 + }, + "_name": "Nix Packages", + "_urls": [ + { + "params": [ + { + "name": "type", + "value": "packages" + }, + { + "name": "query", + "value": "{searchTerms}" + } + ], + "template": "https://search.nixos.org/packages" + } + ], + "id": "Nix Packages" + }, + { + "_definedAliases": [ + "@nw" + ], + "_iconMapObj": { + "16": "https://wiki.nixos.org/favicon.ico" + }, + "_isAppProvided": false, + "_loadPath": "[home-manager]/programs.@name@.profiles.migrateSearchV7.search.engines.\"NixOS Wiki\"", + "_metaData": { + "order": 2 + }, + "_name": "NixOS Wiki", + "_updateInterval": 86400000, + "_urls": [ + { + "template": "https://wiki.nixos.org/index.php?search={searchTerms}" + } + ], + "id": "NixOS Wiki" + }, + { + "_isAppProvided": true, + "_metaData": { + "hidden": true + }, + "id": "bing" + }, + { + "_isAppProvided": true, + "_metaData": {}, + "id": "ddg" + }, + { + "_isAppProvided": true, + "_metaData": { + "alias": "@g" + }, + "id": "google" + } + ], + "metaData": { + "defaultEngineId": "google", + "defaultEngineIdHash": "@hash@", + "privateDefaultEngineId": "ddg", + "privateDefaultEngineIdHash": "@privateHash@", + "useSavedOrder": true + }, + "version": 12 +} diff --git a/tests/modules/programs/firefox/profiles/search/expected-search-without-default.json b/tests/modules/programs/firefox/profiles/search/expected-search-without-default.json index ec1ce14c8..e752f6e46 100644 --- a/tests/modules/programs/firefox/profiles/search/expected-search-without-default.json +++ b/tests/modules/programs/firefox/profiles/search/expected-search-without-default.json @@ -5,14 +5,14 @@ "_metaData": { "order": 1 }, - "_name": "Google" + "id": "google" }, { "_definedAliases": [ "@np" ], "_isAppProvided": false, - "_loadPath": "[home-manager]/programs.@name@.profiles.searchWithoutDefault.search.engines.\"Nix Packages\"", + "_loadPath": "[home-manager]/programs.@name@.profiles.searchWithoutDefault.search.engines.nix-packages", "_metaData": { "order": 2 }, @@ -31,11 +31,12 @@ ], "template": "https://search.nixos.org/packages" } - ] + ], + "id": "nix-packages" } ], "metaData": { "useSavedOrder": true }, - "version": 6 + "version": 12 } diff --git a/tests/modules/programs/firefox/profiles/search/expected-search.json b/tests/modules/programs/firefox/profiles/search/expected-search.json index a661cf3fe..6177027bb 100644 --- a/tests/modules/programs/firefox/profiles/search/expected-search.json +++ b/tests/modules/programs/firefox/profiles/search/expected-search.json @@ -4,9 +4,11 @@ "_definedAliases": [ "@np" ], - "_iconURL": "file:///run/current-system/sw/share/icons/hicolor/scalable/apps/nix-snowflake.svg", + "_iconMapObj": { + "16": "file:///run/current-system/sw/share/icons/hicolor/scalable/apps/nix-snowflake.svg" + }, "_isAppProvided": false, - "_loadPath": "[home-manager]/programs.@name@.profiles.search.search.engines.\"Nix Packages\"", + "_loadPath": "[home-manager]/programs.@name@.profiles.search.search.engines.nix-packages", "_metaData": { "order": 1 }, @@ -25,53 +27,55 @@ ], "template": "https://search.nixos.org/packages" } - ] + ], + "id": "nix-packages" }, { "_definedAliases": [ "@nw" ], - "_iconURL": "https://wiki.nixos.org/favicon.png", - "_iconUpdateURL": "https://wiki.nixos.org/favicon.png", + "_iconMapObj": { + "16": "https://wiki.nixos.org/favicon.ico" + }, "_isAppProvided": false, - "_loadPath": "[home-manager]/programs.@name@.profiles.search.search.engines.\"NixOS Wiki\"", + "_loadPath": "[home-manager]/programs.@name@.profiles.search.search.engines.nixos-wiki", "_metaData": { "order": 2 }, "_name": "NixOS Wiki", - "_updateInterval": 86400000, "_urls": [ { - "template": "https://wiki.nixos.org/index.php?search={searchTerms}" + "template": "https://wiki.nixos.org/w/index.php?search={searchTerms}" } - ] + ], + "id": "nixos-wiki" }, { "_isAppProvided": true, "_metaData": { "hidden": true }, - "_name": "Bing" + "id": "bing" }, { "_isAppProvided": true, "_metaData": {}, - "_name": "DuckDuckGo" + "id": "ddg" }, { "_isAppProvided": true, "_metaData": { "alias": "@g" }, - "_name": "Google" + "id": "google" } ], "metaData": { - "current": "Google", - "hash": null, - "private": "DuckDuckGo", - "privateHash": null, + "defaultEngineId": "google", + "defaultEngineIdHash": "@hash@", + "privateDefaultEngineId": "ddg", + "privateDefaultEngineIdHash": "@privateHash@", "useSavedOrder": true }, - "version": 6 + "version": 12 } diff --git a/tests/modules/programs/firefox/profiles/settings/default.nix b/tests/modules/programs/firefox/profiles/settings/default.nix index 39d329ece..9c27a3515 100644 --- a/tests/modules/programs/firefox/profiles/settings/default.nix +++ b/tests/modules/programs/firefox/profiles/settings/default.nix @@ -1,18 +1,16 @@ modulePath: -{ config, lib, pkgs, ... }: - -with lib; +{ config, lib, ... }: let - cfg = getAttrFromPath modulePath config; + cfg = lib.getAttrFromPath modulePath config; firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath; in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig (setAttrByPath modulePath { + config = lib.mkIf config.test.enableBig (lib.setAttrByPath modulePath { enable = true; profiles = { basic.isDefault = true; diff --git a/tests/modules/programs/firefox/profiles/shared-path.nix b/tests/modules/programs/firefox/profiles/shared-path.nix index e6d4a06d4..6556efcea 100644 --- a/tests/modules/programs/firefox/profiles/shared-path.nix +++ b/tests/modules/programs/firefox/profiles/shared-path.nix @@ -1,26 +1,27 @@ modulePath: { config, lib, ... }: -with lib; - let firefoxMockOverlay = import ../setup-firefox-mock-overlay.nix modulePath; in { imports = [ firefoxMockOverlay ]; - config = mkIf config.test.enableBig (setAttrByPath modulePath { + config = lib.mkIf config.test.enableBig (lib.setAttrByPath modulePath { enable = true; profiles = { main = { isDefault = true; id = 1; - bookmarks = [{ - toolbar = true; - bookmarks = [{ - name = "Home Manager"; - url = "https://wiki.nixos.org/wiki/Home_Manager"; + bookmarks = { + force = true; + settings = [{ + toolbar = true; + bookmarks = [{ + name = "Home Manager"; + url = "https://wiki.nixos.org/wiki/Home_Manager"; + }]; }]; - }]; + }; containers = { "shopping" = { icon = "circle"; @@ -29,11 +30,11 @@ in { }; search = { force = true; - default = "Google"; - privateDefault = "DuckDuckGo"; + default = "google"; + privateDefault = "ddg"; engines = { - "Bing".metaData.hidden = true; - "Google".metaData.alias = "@g"; + bing.metaData.hidden = true; + google.metaData.alias = "@g"; }; }; settings = { diff --git a/tests/modules/programs/firefox/setup-firefox-mock-overlay.nix b/tests/modules/programs/firefox/setup-firefox-mock-overlay.nix index 736eff7ca..861f67081 100644 --- a/tests/modules/programs/firefox/setup-firefox-mock-overlay.nix +++ b/tests/modules/programs/firefox/setup-firefox-mock-overlay.nix @@ -11,6 +11,7 @@ in { "${unwrappedName}" = { name = unwrappedName; extraAttrs = { + applicationName = cfg.wrappedPackageName; binaryName = cfg.wrappedPackageName; gtk3 = null; meta.description = "I pretend to be ${cfg.name}"; diff --git a/tests/modules/programs/firefox/state-version-19_09.nix b/tests/modules/programs/firefox/state-version-19_09.nix index 475705c31..b12a4f6fc 100644 --- a/tests/modules/programs/firefox/state-version-19_09.nix +++ b/tests/modules/programs/firefox/state-version-19_09.nix @@ -1,20 +1,15 @@ modulePath: -{ config, lib, pkgs, ... }: - -with lib; - +{ config, lib, ... }: let - - cfg = getAttrFromPath modulePath config; + cfg = lib.getAttrFromPath modulePath config; firefoxMockOverlay = import ./setup-firefox-mock-overlay.nix modulePath; - in { imports = [ firefoxMockOverlay ]; config = lib.mkIf config.test.enableBig ({ home.stateVersion = "19.09"; - } // setAttrByPath modulePath { enable = true; } // { + } // lib.setAttrByPath modulePath { enable = true; } // { nmt.script = '' assertFileRegex \ home-path/bin/${cfg.wrappedPackageName} \ diff --git a/tests/modules/programs/fish/abbrs.nix b/tests/modules/programs/fish/abbrs.nix index ce89bcb00..a46162cc3 100644 --- a/tests/modules/programs/fish/abbrs.nix +++ b/tests/modules/programs/fish/abbrs.nix @@ -34,6 +34,10 @@ end ''; }; + co = { + command = "git"; + expansion = "checkout"; + }; dotdot = { regex = "^\\.\\.+$"; function = "multicd"; @@ -64,6 +68,8 @@ cd .. end '" + assertFileContains home-files/.config/fish/config.fish \ + "abbr --add --command git -- co checkout" assertFileContains home-files/.config/fish/config.fish \ "abbr --add --function multicd --regex '^\.\.+$' -- dotdot" ''; diff --git a/tests/modules/programs/fish/default.nix b/tests/modules/programs/fish/default.nix index f81ff971e..f7da4d4d0 100644 --- a/tests/modules/programs/fish/default.nix +++ b/tests/modules/programs/fish/default.nix @@ -4,4 +4,5 @@ fish-functions = ./functions.nix; fish-no-functions = ./no-functions.nix; fish-plugins = ./plugins.nix; + fish-manpage = ./manpage.nix; } diff --git a/tests/modules/programs/fish/functions.nix b/tests/modules/programs/fish/functions.nix index b8b5793a5..4bead25b0 100644 --- a/tests/modules/programs/fish/functions.nix +++ b/tests/modules/programs/fish/functions.nix @@ -1,7 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - +{ lib, pkgs, ... }: let func = pkgs.writeText "func.fish" '' diff --git a/tests/modules/programs/fish/manpage.nix b/tests/modules/programs/fish/manpage.nix new file mode 100644 index 000000000..2601b69c7 --- /dev/null +++ b/tests/modules/programs/fish/manpage.nix @@ -0,0 +1,12 @@ +{ lib, pkgs, ... }: { + config = { + programs.fish = { enable = true; }; + + home.packages = [ + (pkgs.runCommand "manpage-with-space" { } '' + mkdir -p $out/share/man/man1 + echo "It works!" >"$out/share/man/man1/hello -inject.1" + '') + ]; + }; +} diff --git a/tests/modules/programs/fish/no-functions.nix b/tests/modules/programs/fish/no-functions.nix index 125ed8841..3caddfd95 100644 --- a/tests/modules/programs/fish/no-functions.nix +++ b/tests/modules/programs/fish/no-functions.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ lib, ... }: { config = { programs.fish = { enable = true; diff --git a/tests/modules/programs/fish/plugins.nix b/tests/modules/programs/fish/plugins.nix index 88684b3b4..3e655e33f 100644 --- a/tests/modules/programs/fish/plugins.nix +++ b/tests/modules/programs/fish/plugins.nix @@ -1,7 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - +{ lib, pkgs, ... }: let fooPluginSrc = pkgs.writeText "fooPluginSrc" ""; diff --git a/tests/modules/programs/getmail/getmail.nix b/tests/modules/programs/getmail/getmail.nix index c460a37e7..8122d6529 100644 --- a/tests/modules/programs/getmail/getmail.nix +++ b/tests/modules/programs/getmail/getmail.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { imports = [ ../../accounts/email-test-accounts.nix ]; diff --git a/tests/modules/programs/gh-dash/config.nix b/tests/modules/programs/gh-dash/config.nix index cb07d13aa..cec1b8b3e 100644 --- a/tests/modules/programs/gh-dash/config.nix +++ b/tests/modules/programs/gh-dash/config.nix @@ -1,11 +1,14 @@ { - programs.gh-dash = { - enable = true; - settings = { - prSections = [{ - title = "My Pull Requests"; - filters = "is:open author:@me"; - }]; + programs = { + gh.enable = true; + gh-dash = { + enable = true; + settings = { + prSections = [{ + title = "My Pull Requests"; + filters = "is:open author:@me"; + }]; + }; }; }; diff --git a/tests/modules/programs/git-worktree-switcher/fish.nix b/tests/modules/programs/git-worktree-switcher/fish.nix index b6b29c2ae..946cfa754 100644 --- a/tests/modules/programs/git-worktree-switcher/fish.nix +++ b/tests/modules/programs/git-worktree-switcher/fish.nix @@ -1,5 +1,3 @@ -{ ... }: - { programs = { fish.enable = true; diff --git a/tests/modules/programs/git-worktree-switcher/zsh.nix b/tests/modules/programs/git-worktree-switcher/zsh.nix index 5e0672763..31028441d 100644 --- a/tests/modules/programs/git-worktree-switcher/zsh.nix +++ b/tests/modules/programs/git-worktree-switcher/zsh.nix @@ -1,5 +1,3 @@ -{ ... }: - { programs = { zsh.enable = true; diff --git a/tests/modules/programs/git/git-with-msmtp-expected.conf b/tests/modules/programs/git/git-with-msmtp-expected.conf index 3d636a8b0..9525d14b2 100644 --- a/tests/modules/programs/git/git-with-msmtp-expected.conf +++ b/tests/modules/programs/git/git-with-msmtp-expected.conf @@ -14,7 +14,7 @@ [sendemail "hm@example.com"] envelopeSender = "auto" from = "H. M. Test " - smtpServer = "@msmtp@/bin/msmtp" + sendmailCmd = "@msmtp@/bin/msmtp" [user] email = "hm@example.com" diff --git a/tests/modules/programs/git/git-with-msmtp.nix b/tests/modules/programs/git/git-with-msmtp.nix index 5b5416189..eec269c76 100644 --- a/tests/modules/programs/git/git-with-msmtp.nix +++ b/tests/modules/programs/git/git-with-msmtp.nix @@ -31,7 +31,7 @@ assertGitConfig "sendemail.hm@example.com.from" "H. M. Test " assertGitConfig "sendemail.hm-account.from" "H. M. Test Jr. " - assertGitConfig "sendemail.hm@example.com.smtpServer" "${pkgs.msmtp}/bin/msmtp" + assertGitConfig "sendemail.hm@example.com.sendmailCmd" "${pkgs.msmtp}/bin/msmtp" assertGitConfig "sendemail.hm@example.com.envelopeSender" "auto" ''; } diff --git a/tests/modules/programs/gnome-shell/gnome-shell.nix b/tests/modules/programs/gnome-shell/gnome-shell.nix index b9cc327d9..b6f6c49f6 100644 --- a/tests/modules/programs/gnome-shell/gnome-shell.nix +++ b/tests/modules/programs/gnome-shell/gnome-shell.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let dummy-gnome-shell-extensions = pkgs.runCommand "dummy-package" { } '' mkdir -p $out/share/gnome-shell/extensions/dummy-package @@ -31,7 +28,7 @@ let "test-extension-uuid" ]; - actualEnabledExtensions = catAttrs "value" + actualEnabledExtensions = lib.catAttrs "value" config.dconf.settings."org/gnome/shell".enabled-extensions.value; in { @@ -62,8 +59,8 @@ in { message = "Expected disable-user-extensions to be false."; } { - assertion = - all (e: elem e actualEnabledExtensions) expectedEnabledExtensions; + assertion = lib.all (e: lib.elem e actualEnabledExtensions) + expectedEnabledExtensions; message = '' Expected enabled-extensions to contain all of: ${toString expectedEnabledExtensions} diff --git a/tests/modules/programs/gpg/override-defaults.nix b/tests/modules/programs/gpg/override-defaults.nix index e41043395..5e9275d83 100644 --- a/tests/modules/programs/gpg/override-defaults.nix +++ b/tests/modules/programs/gpg/override-defaults.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { config = { programs.gpg = { enable = true; diff --git a/tests/modules/programs/granted/default.nix b/tests/modules/programs/granted/default.nix index da462752b..a4e79212b 100644 --- a/tests/modules/programs/granted/default.nix +++ b/tests/modules/programs/granted/default.nix @@ -1,4 +1,6 @@ { - granted-integration-enabled = ./integration-enabled.nix; - granted-integration-disabled = ./integration-disabled.nix; + granted-zsh-integration-enabled = ./zsh-integration-enabled.nix; + granted-zsh-integration-disabled = ./zsh-integration-disabled.nix; + granted-fish-integration-enabled = ./fish-integration-enabled.nix; + granted-fish-integration-disabled = ./fish-integration-disabled.nix; } diff --git a/tests/modules/programs/granted/fish-integration-disabled.nix b/tests/modules/programs/granted/fish-integration-disabled.nix new file mode 100644 index 000000000..9518c8934 --- /dev/null +++ b/tests/modules/programs/granted/fish-integration-disabled.nix @@ -0,0 +1,11 @@ +{ + programs = { + granted.enable = true; + granted.enableFishIntegration = false; + fish.enable = true; + }; + + nmt.script = '' + assertPathNotExists home-files/.config/fish/functions/assume.fish + ''; +} diff --git a/tests/modules/programs/granted/fish-integration-enabled.nix b/tests/modules/programs/granted/fish-integration-enabled.nix new file mode 100644 index 000000000..80e30873a --- /dev/null +++ b/tests/modules/programs/granted/fish-integration-enabled.nix @@ -0,0 +1,10 @@ +{ + programs = { + granted.enable = true; + fish.enable = true; + }; + + nmt.script = '' + assertFileExists home-files/.config/fish/functions/assume.fish + ''; +} diff --git a/tests/modules/programs/granted/integration-disabled.nix b/tests/modules/programs/granted/zsh-integration-disabled.nix similarity index 100% rename from tests/modules/programs/granted/integration-disabled.nix rename to tests/modules/programs/granted/zsh-integration-disabled.nix diff --git a/tests/modules/programs/granted/integration-enabled.nix b/tests/modules/programs/granted/zsh-integration-enabled.nix similarity index 100% rename from tests/modules/programs/granted/integration-enabled.nix rename to tests/modules/programs/granted/zsh-integration-enabled.nix diff --git a/tests/modules/programs/helix/example-settings.nix b/tests/modules/programs/helix/example-settings.nix index 69a5ef557..e345725e4 100644 --- a/tests/modules/programs/helix/example-settings.nix +++ b/tests/modules/programs/helix/example-settings.nix @@ -1,6 +1,4 @@ -{ config, ... }: - -{ +{ config, ... }: { programs.helix = { enable = true; @@ -18,6 +16,12 @@ }; }; + extraConfig = '' + [keys.normal.G] + G = "goto_file_end" + g = "goto_file_start" + ''; + languages = { language-server.typescript-language-server = let typescript-language-server = config.lib.test.mkStubPackage { diff --git a/tests/modules/programs/helix/settings-expected.toml b/tests/modules/programs/helix/settings-expected.toml index 91682f0ae..5e218ed77 100644 --- a/tests/modules/programs/helix/settings-expected.toml +++ b/tests/modules/programs/helix/settings-expected.toml @@ -12,3 +12,7 @@ esc = ["collapse_selection", "keep_primary_selection"] q = ":q" space = "file_picker" w = ":w" + +[keys.normal.G] +G = "goto_file_end" +g = "goto_file_start" diff --git a/tests/modules/programs/jqp/basic-configuration.nix b/tests/modules/programs/jqp/basic-configuration.nix new file mode 100644 index 000000000..23b79310a --- /dev/null +++ b/tests/modules/programs/jqp/basic-configuration.nix @@ -0,0 +1,14 @@ +{ + programs = { + jqp = { + enable = true; + settings = { theme.name = "catppuccin-frappe"; }; + }; + }; + + nmt.script = '' + assertFileExists home-files/.jqp.yaml + assertFileContent home-files/.jqp.yaml \ + ${./basic-configuration.yaml} + ''; +} diff --git a/tests/modules/programs/jqp/basic-configuration.yaml b/tests/modules/programs/jqp/basic-configuration.yaml new file mode 100644 index 000000000..57f744234 --- /dev/null +++ b/tests/modules/programs/jqp/basic-configuration.yaml @@ -0,0 +1,2 @@ +theme: + name: catppuccin-frappe diff --git a/tests/modules/programs/jqp/default.nix b/tests/modules/programs/jqp/default.nix new file mode 100644 index 000000000..3ab8e24cb --- /dev/null +++ b/tests/modules/programs/jqp/default.nix @@ -0,0 +1 @@ +{ jqp-basic-configuration = ./basic-configuration.nix; } diff --git a/tests/modules/programs/k9s/empty-settings.nix b/tests/modules/programs/k9s/empty-settings.nix index 6ff4276f7..05f859ee2 100644 --- a/tests/modules/programs/k9s/empty-settings.nix +++ b/tests/modules/programs/k9s/empty-settings.nix @@ -3,7 +3,7 @@ { programs.k9s.enable = true; - xdg.enable = lib.mkIf pkgs.stdenv.isDarwin (lib.mkForce false); + xdg.enable = lib.mkIf pkgs.stdenv.isDarwin false; nmt.script = let configDir = if !pkgs.stdenv.isDarwin then diff --git a/tests/modules/programs/k9s/example-settings.nix b/tests/modules/programs/k9s/example-settings.nix index 0000d81da..65d624e93 100644 --- a/tests/modules/programs/k9s/example-settings.nix +++ b/tests/modules/programs/k9s/example-settings.nix @@ -1,7 +1,7 @@ { config, pkgs, lib, ... }: { - xdg.enable = lib.mkIf pkgs.stdenv.isDarwin (lib.mkForce false); + xdg.enable = lib.mkIf pkgs.stdenv.isDarwin false; programs.k9s = { enable = true; diff --git a/tests/modules/programs/kitty/example-settings-expected.conf b/tests/modules/programs/kitty/example-settings-expected.conf index 41a9cb772..b52d34d44 100644 --- a/tests/modules/programs/kitty/example-settings-expected.conf +++ b/tests/modules/programs/kitty/example-settings-expected.conf @@ -12,6 +12,9 @@ enable_audio_bell no scrollback_lines 10000 update_check_interval 0 +action_alias launch_tab launch --cwd=current --type=tab +action_alias launch_window launch --cwd=current --type=os-window + map ctrl+c copy_or_interrupt map ctrl+f>2 set_font_size 20 diff --git a/tests/modules/programs/kitty/example-settings.nix b/tests/modules/programs/kitty/example-settings.nix index d02c04c55..cd7a9a327 100644 --- a/tests/modules/programs/kitty/example-settings.nix +++ b/tests/modules/programs/kitty/example-settings.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ lib, pkgs, ... }: { config = { programs.kitty = { enable = true; @@ -28,6 +24,11 @@ with lib; "ctrl+f>2" = "set_font_size 20"; }; + actionAliases = { + "launch_tab" = "launch --cwd=current --type=tab"; + "launch_window" = "launch --cwd=current --type=os-window"; + }; + environment = { LS_COLORS = "1"; }; }; diff --git a/tests/modules/programs/kitty/null-shellIntegration-expected.conf b/tests/modules/programs/kitty/null-shellIntegration-expected.conf index df3ae5984..75386d91e 100644 --- a/tests/modules/programs/kitty/null-shellIntegration-expected.conf +++ b/tests/modules/programs/kitty/null-shellIntegration-expected.conf @@ -6,3 +6,4 @@ + diff --git a/tests/modules/programs/kitty/null-shellIntegration.nix b/tests/modules/programs/kitty/null-shellIntegration.nix index 293249d69..0346ee92b 100644 --- a/tests/modules/programs/kitty/null-shellIntegration.nix +++ b/tests/modules/programs/kitty/null-shellIntegration.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.kitty = { diff --git a/tests/modules/programs/kubecolor/default.nix b/tests/modules/programs/kubecolor/default.nix index 4445de604..fe8404265 100644 --- a/tests/modules/programs/kubecolor/default.nix +++ b/tests/modules/programs/kubecolor/default.nix @@ -2,4 +2,6 @@ kubecolor-empty-config = ./empty-config.nix; kubecolor-example-config-default-paths = ./example-config-default-paths.nix; kubecolor-example-config-xdg-paths = ./example-config-xdg-paths.nix; + kubecolor-does-have-openshift = ./does-have-openshift.nix; + kubecolor-does-not-have-openshift = ./does-not-have-openshift.nix; } diff --git a/tests/modules/programs/kubecolor/does-have-openshift.nix b/tests/modules/programs/kubecolor/does-have-openshift.nix new file mode 100644 index 000000000..015468865 --- /dev/null +++ b/tests/modules/programs/kubecolor/does-have-openshift.nix @@ -0,0 +1,33 @@ +{ config, pkgs, ... }: + +{ + programs.kubecolor = { + enable = true; + package = config.lib.test.mkStubPackage { + name = "kubecolor"; + version = "0.4.0"; + }; + enableAlias = true; + }; + programs.zsh = { + enable = true; + package = config.lib.test.mkStubPackage { + name = "zsh"; + version = "5.9"; + }; + }; + nixpkgs.overlays = [ + (self: super: rec { + openshift = config.lib.test.mkStubPackage { + name = "openshift"; + version = "4.16.0"; + }; + }) + ]; + home.packages = [ pkgs.openshift ]; + + nmt.script = '' + assertFileRegex 'home-files/.zshrc' '^alias.* oc=.*' + ''; +} + diff --git a/tests/modules/programs/kubecolor/does-not-have-openshift.nix b/tests/modules/programs/kubecolor/does-not-have-openshift.nix new file mode 100644 index 000000000..1f4cb0d7c --- /dev/null +++ b/tests/modules/programs/kubecolor/does-not-have-openshift.nix @@ -0,0 +1,24 @@ +{ config, ... }: + +{ + programs.kubecolor = { + enable = true; + package = config.lib.test.mkStubPackage { + name = "kubecolor"; + version = "0.4.0"; + }; + enableAlias = true; + }; + programs.zsh = { + enable = true; + package = config.lib.test.mkStubPackage { + name = "zsh"; + version = "5.9"; + }; + }; + + nmt.script = '' + assertFileNotRegex 'home-files/.zshrc' '^alias.* oc=.*' + ''; +} + diff --git a/tests/modules/programs/lazydocker/custom-settings.nix b/tests/modules/programs/lazydocker/custom-settings.nix new file mode 100644 index 000000000..e57b530ba --- /dev/null +++ b/tests/modules/programs/lazydocker/custom-settings.nix @@ -0,0 +1,18 @@ +{ ... }: { + programs.lazydocker = { + enable = true; + settings = { + commandTemplates.dockerCompose = "docker compose"; + gui.theme = { + activeBorderColor = [ "red" "bold" ]; + inactiveBorderColor = [ "blue" ]; + }; + }; + }; + test.stubs.lazydocker = { }; + nmt.script = '' + assertFileExists home-files/.config/lazydocker/config.yml + assertFileContent home-files/.config/lazydocker/config.yml \ + ${./custom-settings.yml} + ''; +} diff --git a/tests/modules/programs/lazydocker/custom-settings.yml b/tests/modules/programs/lazydocker/custom-settings.yml new file mode 100644 index 000000000..91022449f --- /dev/null +++ b/tests/modules/programs/lazydocker/custom-settings.yml @@ -0,0 +1,9 @@ +commandTemplates: + dockerCompose: docker compose +gui: + theme: + activeBorderColor: + - red + - bold + inactiveBorderColor: + - blue diff --git a/tests/modules/programs/lazydocker/default-settings.nix b/tests/modules/programs/lazydocker/default-settings.nix new file mode 100644 index 000000000..55dee658a --- /dev/null +++ b/tests/modules/programs/lazydocker/default-settings.nix @@ -0,0 +1,9 @@ +{ ... }: { + programs.lazydocker.enable = true; + test.stubs.lazydocker = { }; + nmt.script = '' + assertFileExists home-files/.config/lazydocker/config.yml + assertFileContent home-files/.config/lazydocker/config.yml \ + ${./default.yml} + ''; +} diff --git a/tests/modules/programs/lazydocker/default.nix b/tests/modules/programs/lazydocker/default.nix new file mode 100644 index 000000000..7478fb9dc --- /dev/null +++ b/tests/modules/programs/lazydocker/default.nix @@ -0,0 +1,5 @@ +{ + lazydocker-default-settings = ./default-settings.nix; + lazydocker-custom-settings = ./custom-settings.nix; +} + diff --git a/tests/modules/programs/lazydocker/default.yml b/tests/modules/programs/lazydocker/default.yml new file mode 100644 index 000000000..abc65b784 --- /dev/null +++ b/tests/modules/programs/lazydocker/default.yml @@ -0,0 +1,2 @@ +commandTemplates: + dockerCompose: docker compose diff --git a/tests/modules/programs/lieer/lieer.nix b/tests/modules/programs/lieer/lieer.nix index 5e7847464..e6786c92d 100644 --- a/tests/modules/programs/lieer/lieer.nix +++ b/tests/modules/programs/lieer/lieer.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { imports = [ ../../accounts/email-test-accounts.nix ]; config = { diff --git a/tests/modules/programs/looking-glass-client/empty-settings.nix b/tests/modules/programs/looking-glass-client/empty-settings.nix index 10c177a9e..5b2a8b9c4 100644 --- a/tests/modules/programs/looking-glass-client/empty-settings.nix +++ b/tests/modules/programs/looking-glass-client/empty-settings.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { config = { programs.looking-glass-client = { enable = true; diff --git a/tests/modules/programs/looking-glass-client/example-settings.nix b/tests/modules/programs/looking-glass-client/example-settings.nix index 6ac8f0185..c85701580 100644 --- a/tests/modules/programs/looking-glass-client/example-settings.nix +++ b/tests/modules/programs/looking-glass-client/example-settings.nix @@ -1,8 +1,4 @@ -{ config, lib, ... }: - -with lib; - -{ +{ config, ... }: { config = { programs.looking-glass-client = { enable = true; diff --git a/tests/modules/programs/man/apropos.nix b/tests/modules/programs/man/apropos.nix index a8ec35ead..ee30f8f8c 100644 --- a/tests/modules/programs/man/apropos.nix +++ b/tests/modules/programs/man/apropos.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.man = { diff --git a/tests/modules/programs/man/no-manpath.nix b/tests/modules/programs/man/no-manpath.nix index 1b8cfb40c..dc3a3a0cb 100644 --- a/tests/modules/programs/man/no-manpath.nix +++ b/tests/modules/programs/man/no-manpath.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.man = { enable = true; }; diff --git a/tests/modules/programs/mergiraf/basic-configuration.nix b/tests/modules/programs/mergiraf/basic-configuration.nix new file mode 100644 index 000000000..3d8688ad7 --- /dev/null +++ b/tests/modules/programs/mergiraf/basic-configuration.nix @@ -0,0 +1,13 @@ +{ config, lib, ... }: + +{ + programs.git.enable = true; + programs.mergiraf.enable = true; + + nmt.script = '' + assertFileContent "home-files/.config/git/config" ${./mergiraf-git.conf} + assertFileContent "home-files/.config/git/attributes" ${ + ./mergiraf-git-attributes.conf + } + ''; +} diff --git a/tests/modules/programs/mergiraf/default.nix b/tests/modules/programs/mergiraf/default.nix new file mode 100644 index 000000000..67d8916b7 --- /dev/null +++ b/tests/modules/programs/mergiraf/default.nix @@ -0,0 +1 @@ +{ mergiraf-basic-configuration = ./basic-configuration.nix; } diff --git a/tests/modules/programs/mergiraf/mergiraf-git-attributes.conf b/tests/modules/programs/mergiraf/mergiraf-git-attributes.conf new file mode 100644 index 000000000..789ed5db5 --- /dev/null +++ b/tests/modules/programs/mergiraf/mergiraf-git-attributes.conf @@ -0,0 +1 @@ +* merge=mergiraf diff --git a/tests/modules/programs/mergiraf/mergiraf-git.conf b/tests/modules/programs/mergiraf/mergiraf-git.conf new file mode 100644 index 000000000..46da0369f --- /dev/null +++ b/tests/modules/programs/mergiraf/mergiraf-git.conf @@ -0,0 +1,9 @@ +[gpg] + format = "openpgp" + +[gpg "openpgp"] + program = "@gnupg@/bin/gpg" + +[merge "mergiraf"] + driver = "@mergiraf@/bin/mergiraf merge --git %O %A %B -s %S -x %X -y %Y -p %P -l %L" + name = "mergiraf" diff --git a/tests/modules/programs/mods/basic-configuration.nix b/tests/modules/programs/mods/basic-configuration.nix new file mode 100644 index 000000000..31b97276a --- /dev/null +++ b/tests/modules/programs/mods/basic-configuration.nix @@ -0,0 +1,22 @@ +{ config, pkgs, ... }: { + config = { + programs.mods = { + enable = true; + package = pkgs.writeScriptBin "dummy-mods" ""; + settings = { + default-model = "llama3.2"; + apis = { + ollama = { + base-url = "http://localhost:11434/api"; + models = { "llama3.2" = { max-input-chars = 650000; }; }; + }; + }; + }; + }; + nmt.script = '' + assertFileExists home-files/.config/mods/mods.yml + assertFileContent home-files/.config/mods/mods.yml \ + ${./basic-configuration.yml} + ''; + }; +} diff --git a/tests/modules/programs/mods/basic-configuration.yml b/tests/modules/programs/mods/basic-configuration.yml new file mode 100644 index 000000000..aec63e220 --- /dev/null +++ b/tests/modules/programs/mods/basic-configuration.yml @@ -0,0 +1,7 @@ +apis: + ollama: + base-url: http://localhost:11434/api + models: + llama3.2: + max-input-chars: 650000 +default-model: llama3.2 diff --git a/tests/modules/programs/mods/default.nix b/tests/modules/programs/mods/default.nix new file mode 100644 index 000000000..cf9909b1b --- /dev/null +++ b/tests/modules/programs/mods/default.nix @@ -0,0 +1 @@ +{ mods-basic-configuration = ./basic-configuration.nix; } diff --git a/tests/modules/programs/mujmap/mujmap-defaults.nix b/tests/modules/programs/mujmap/mujmap-defaults.nix index 704978997..d1a71f180 100644 --- a/tests/modules/programs/mujmap/mujmap-defaults.nix +++ b/tests/modules/programs/mujmap/mujmap-defaults.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { imports = [ ../../accounts/email-test-accounts.nix ]; config = { diff --git a/tests/modules/programs/mujmap/mujmap-fqdn-and-session-url-specified.nix b/tests/modules/programs/mujmap/mujmap-fqdn-and-session-url-specified.nix index 03c3f542e..6ae87f832 100644 --- a/tests/modules/programs/mujmap/mujmap-fqdn-and-session-url-specified.nix +++ b/tests/modules/programs/mujmap/mujmap-fqdn-and-session-url-specified.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { imports = [ ../../accounts/email-test-accounts.nix ]; config = { diff --git a/tests/modules/programs/neomutt/hm-example.com-expected b/tests/modules/programs/neomutt/hm-example.com-expected index e31f0d01a..28d4c56bb 100644 --- a/tests/modules/programs/neomutt/hm-example.com-expected +++ b/tests/modules/programs/neomutt/hm-example.com-expected @@ -13,10 +13,6 @@ set sort = "threads" set smtp_pass="`password-command`" set smtp_url='smtps://home.manager@smtp.example.com' - - - - # MRA section set folder='/home/hm-user/Mail/hm@example.com' set from='hm@example.com' @@ -32,6 +28,7 @@ color status cyan default unset signature + # notmuch section set nm_default_uri = "notmuch:///home/hm-user/Mail" virtual-mailboxes "My INBOX" "notmuch://?query=tag%3Ainbox" diff --git a/tests/modules/programs/neomutt/hm-example.com-gpg-expected.conf b/tests/modules/programs/neomutt/hm-example.com-gpg-expected.conf index f37710719..4c8d65e16 100644 --- a/tests/modules/programs/neomutt/hm-example.com-gpg-expected.conf +++ b/tests/modules/programs/neomutt/hm-example.com-gpg-expected.conf @@ -13,10 +13,6 @@ set sort = "threads" set smtp_pass="`password-command`" set smtp_url='smtps://home.manager@smtp.example.com' - - - - # MRA section set folder='/home/hm-user/Mail/hm@example.com' set from='hm@example.com' diff --git a/tests/modules/programs/neomutt/hm-example.com-imap-expected.conf b/tests/modules/programs/neomutt/hm-example.com-imap-expected.conf index f5e9116d1..e87fbdc3f 100644 --- a/tests/modules/programs/neomutt/hm-example.com-imap-expected.conf +++ b/tests/modules/programs/neomutt/hm-example.com-imap-expected.conf @@ -13,10 +13,6 @@ set sort = "threads" set smtp_pass="`password-command`" set smtp_url='smtps://home.manager@smtp.example.com' - - - - # MRA section set folder='imaps://home.manager@imap.example.com:993' set from='hm@example.com' diff --git a/tests/modules/programs/neomutt/hm-example.com-msmtp-expected.conf b/tests/modules/programs/neomutt/hm-example.com-msmtp-expected.conf index 6d4a845d0..12c7d23d5 100644 --- a/tests/modules/programs/neomutt/hm-example.com-msmtp-expected.conf +++ b/tests/modules/programs/neomutt/hm-example.com-msmtp-expected.conf @@ -12,10 +12,6 @@ set sort = "threads" # MTA section set sendmail='msmtpq --read-envelope-from --read-recipients' - - - - # MRA section set folder='/home/hm-user/Mail/hm@example.com' set from='hm@example.com' diff --git a/tests/modules/programs/neomutt/hm-example.com-no-folder-change-expected.conf b/tests/modules/programs/neomutt/hm-example.com-no-folder-change-expected.conf index 44def8ae7..a5a8382a9 100644 --- a/tests/modules/programs/neomutt/hm-example.com-no-folder-change-expected.conf +++ b/tests/modules/programs/neomutt/hm-example.com-no-folder-change-expected.conf @@ -12,10 +12,6 @@ set sort = "threads" # MTA section set sendmail='msmtpq --read-envelope-from --read-recipients' - - - - # MRA section set from='hm@example.com' set postponed='+Drafts' diff --git a/tests/modules/programs/neomutt/hm-example.com-signature-command-expected b/tests/modules/programs/neomutt/hm-example.com-signature-command-expected index 57825af4e..ab4c63824 100644 --- a/tests/modules/programs/neomutt/hm-example.com-signature-command-expected +++ b/tests/modules/programs/neomutt/hm-example.com-signature-command-expected @@ -13,10 +13,6 @@ set sort = "threads" set smtp_pass="`password-command`" set smtp_url='smtps://home.manager@smtp.example.com' - - - - # MRA section set folder='/home/hm-user/Mail/hm@example.com' set from='hm@example.com' @@ -32,6 +28,7 @@ color status cyan default set signature = "/nix/store/00000000000000000000000000000000-signature|" + # notmuch section set nm_default_uri = "notmuch:///home/hm-user/Mail" virtual-mailboxes "My INBOX" "notmuch://?query=tag%3Ainbox" diff --git a/tests/modules/programs/neomutt/hm-example.com-signature-expected b/tests/modules/programs/neomutt/hm-example.com-signature-expected index c17314ed5..017bd234e 100644 --- a/tests/modules/programs/neomutt/hm-example.com-signature-expected +++ b/tests/modules/programs/neomutt/hm-example.com-signature-expected @@ -13,10 +13,6 @@ set sort = "threads" set smtp_pass="`password-command`" set smtp_url='smtps://home.manager@smtp.example.com' - - - - # MRA section set folder='/home/hm-user/Mail/hm@example.com' set from='hm@example.com' @@ -32,6 +28,7 @@ color status cyan default set signature = /nix/store/00000000000000000000000000000000-signature.txt + # notmuch section set nm_default_uri = "notmuch:///home/hm-user/Mail" virtual-mailboxes "My INBOX" "notmuch://?query=tag%3Ainbox" diff --git a/tests/modules/programs/neomutt/hm-example.com-starttls-expected b/tests/modules/programs/neomutt/hm-example.com-starttls-expected index 59aa3d1cd..7dd5a8edc 100644 --- a/tests/modules/programs/neomutt/hm-example.com-starttls-expected +++ b/tests/modules/programs/neomutt/hm-example.com-starttls-expected @@ -13,10 +13,6 @@ set sort = "threads" set smtp_pass="`password-command`" set smtp_url='smtp://home.manager@smtp.example.com' - - - - # MRA section set folder='/home/hm-user/Mail/hm@example.com' set from='hm@example.com' @@ -32,6 +28,7 @@ color status cyan default unset signature + # notmuch section set nm_default_uri = "notmuch:///home/hm-user/Mail" virtual-mailboxes "My INBOX" "notmuch://?query=tag%3Ainbox" diff --git a/tests/modules/programs/neomutt/hm-example.com-unmailboxes-expected.conf b/tests/modules/programs/neomutt/hm-example.com-unmailboxes-expected.conf index 35822ceee..053a39204 100644 --- a/tests/modules/programs/neomutt/hm-example.com-unmailboxes-expected.conf +++ b/tests/modules/programs/neomutt/hm-example.com-unmailboxes-expected.conf @@ -14,10 +14,6 @@ set sort = "threads" # MTA section set sendmail='msmtpq --read-envelope-from --read-recipients' - - - - # MRA section set folder='/home/hm-user/Mail/hm@example.com' set from='hm@example.com' diff --git a/tests/modules/programs/neomutt/neomutt-expected.conf b/tests/modules/programs/neomutt/neomutt-expected.conf index 2a45234dd..52e6db9db 100644 --- a/tests/modules/programs/neomutt/neomutt-expected.conf +++ b/tests/modules/programs/neomutt/neomutt-expected.conf @@ -4,31 +4,22 @@ set message_cachedir = "/home/hm-user/.cache/neomutt/messages/" set editor = "$EDITOR" set implicit_autoview = yes set crypt_use_gpgme = yes - alternative_order text/enriched text/plain text - set delete = yes - -# Binds - - # Macros - # Register accounts -# register account hm@example.com + +## register account hm@example.com mailboxes "/home/hm-user/Mail/hm@example.com/Inbox" folder-hook /home/hm-user/Mail/hm@example.com/ " \ - source /home/hm-user/.config/neomutt/hm@example.com " - + source /home/hm-user/.config/neomutt/hm@example.com " # Source primary account source /home/hm-user/.config/neomutt/hm@example.com # Extra configuration - - diff --git a/tests/modules/programs/neomutt/neomutt-not-primary-expected.conf b/tests/modules/programs/neomutt/neomutt-not-primary-expected.conf index 47dc81739..57ee6bce0 100644 --- a/tests/modules/programs/neomutt/neomutt-not-primary-expected.conf +++ b/tests/modules/programs/neomutt/neomutt-not-primary-expected.conf @@ -4,31 +4,22 @@ set message_cachedir = "/home/hm-user/.cache/neomutt/messages/" set editor = "$EDITOR" set implicit_autoview = yes set crypt_use_gpgme = yes - alternative_order text/enriched text/plain text - set delete = yes - -# Binds - - # Macros - # Register accounts -# register account hm-account + +## register account hm-account mailboxes "/home/hm-user/Mail/hm-account/Inbox" folder-hook /home/hm-user/Mail/hm-account/ " \ - source /home/hm-user/.config/neomutt/hm-account " - + source /home/hm-user/.config/neomutt/hm-account " # Source primary account source /home/hm-user/.config/neomutt/hm-account # Extra configuration - - diff --git a/tests/modules/programs/neomutt/neomutt-not-primary.nix b/tests/modules/programs/neomutt/neomutt-not-primary.nix index db1f2de64..8389f9709 100644 --- a/tests/modules/programs/neomutt/neomutt-not-primary.nix +++ b/tests/modules/programs/neomutt/neomutt-not-primary.nix @@ -10,7 +10,7 @@ nmt.script = '' assertFileExists home-files/.config/neomutt/neomuttrc - assertFileContent home-files/.config/neomutt/neomuttrc ${ + assertFileContent $(normalizeStorePaths home-files/.config/neomutt/neomuttrc) ${ ./neomutt-not-primary-expected.conf } ''; diff --git a/tests/modules/programs/neomutt/neomutt-with-binds-expected.conf b/tests/modules/programs/neomutt/neomutt-with-binds-expected.conf index 05736749f..8c25c3b09 100644 --- a/tests/modules/programs/neomutt/neomutt-with-binds-expected.conf +++ b/tests/modules/programs/neomutt/neomutt-with-binds-expected.conf @@ -4,13 +4,10 @@ set message_cachedir = "/home/hm-user/.cache/neomutt/messages/" set editor = "$EDITOR" set implicit_autoview = yes set crypt_use_gpgme = yes - alternative_order text/enriched text/plain text - set delete = yes - # Binds bind editor "complete-query" bind index,pager \Cp "sidebar-prev" @@ -18,19 +15,16 @@ bind index,pager \Cp "sidebar-prev" # Macros macro index s "?" macro index,pager c "?^K=" - # Register accounts -# register account hm@example.com + +## register account hm@example.com mailboxes "/home/hm-user/Mail/hm@example.com/Inbox" folder-hook /home/hm-user/Mail/hm@example.com/ " \ - source /home/hm-user/.config/neomutt/hm@example.com " - + source /home/hm-user/.config/neomutt/hm@example.com " # Source primary account source /home/hm-user/.config/neomutt/hm@example.com # Extra configuration - - diff --git a/tests/modules/programs/neomutt/neomutt-with-binds-with-warning.nix b/tests/modules/programs/neomutt/neomutt-with-binds-with-warning.nix index f9d144dfd..bb0a0f89b 100644 --- a/tests/modules/programs/neomutt/neomutt-with-binds-with-warning.nix +++ b/tests/modules/programs/neomutt/neomutt-with-binds-with-warning.nix @@ -52,10 +52,10 @@ nmt.script = '' assertFileExists home-files/.config/neomutt/neomuttrc assertFileExists home-files/.config/neomutt/hm@example.com - assertFileContent home-files/.config/neomutt/neomuttrc ${ + assertFileContent $(normalizeStorePaths home-files/.config/neomutt/neomuttrc) ${ ./neomutt-with-binds-expected.conf } - assertFileContent home-files/.config/neomutt/hm@example.com ${ + assertFileContent $(normalizeStorePaths home-files/.config/neomutt/hm@example.com) ${ ./hm-example.com-expected } ''; diff --git a/tests/modules/programs/neomutt/neomutt-with-binds.nix b/tests/modules/programs/neomutt/neomutt-with-binds.nix index 7f97ae9e8..6fd8b8ff8 100644 --- a/tests/modules/programs/neomutt/neomutt-with-binds.nix +++ b/tests/modules/programs/neomutt/neomutt-with-binds.nix @@ -48,10 +48,10 @@ nmt.script = '' assertFileExists home-files/.config/neomutt/neomuttrc assertFileExists home-files/.config/neomutt/hm@example.com - assertFileContent home-files/.config/neomutt/neomuttrc ${ + assertFileContent $(normalizeStorePaths home-files/.config/neomutt/neomuttrc) ${ ./neomutt-with-binds-expected.conf } - assertFileContent home-files/.config/neomutt/hm@example.com ${ + assertFileContent $(normalizeStorePaths home-files/.config/neomutt/hm@example.com) ${ ./hm-example.com-expected } ''; diff --git a/tests/modules/programs/neomutt/neomutt-with-gpg.nix b/tests/modules/programs/neomutt/neomutt-with-gpg.nix index 1f542d747..9b43fc703 100644 --- a/tests/modules/programs/neomutt/neomutt-with-gpg.nix +++ b/tests/modules/programs/neomutt/neomutt-with-gpg.nix @@ -17,7 +17,7 @@ nmt.script = '' assertFileExists home-files/.config/neomutt/neomuttrc assertFileExists home-files/.config/neomutt/hm@example.com - assertFileContent home-files/.config/neomutt/neomuttrc ${ + assertFileContent $(normalizeStorePaths home-files/.config/neomutt/neomuttrc) ${ ./neomutt-expected.conf } assertFileContent home-files/.config/neomutt/hm@example.com ${ diff --git a/tests/modules/programs/neomutt/neomutt-with-imap-expected.conf b/tests/modules/programs/neomutt/neomutt-with-imap-expected.conf index 02f03f6ec..01b5955c4 100644 --- a/tests/modules/programs/neomutt/neomutt-with-imap-expected.conf +++ b/tests/modules/programs/neomutt/neomutt-with-imap-expected.conf @@ -4,32 +4,23 @@ set message_cachedir = "/home/hm-user/.cache/neomutt/messages/" set editor = "$EDITOR" set implicit_autoview = yes set crypt_use_gpgme = yes - alternative_order text/enriched text/plain text - set delete = yes - -# Binds - - # Macros - # Register accounts set account_command = '/nix/store/00000000000000000000000000000000-account-command.sh/bin/account-command.sh' -# register account hm@example.com + +## register account hm@example.com mailboxes "imaps://home.manager@imap.example.com:993/Inbox" account-hook imaps://home.manager@imap.example.com:993/ " \ - source /home/hm-user/.config/neomutt/hm@example.com " - + source /home/hm-user/.config/neomutt/hm@example.com " # Source primary account source /home/hm-user/.config/neomutt/hm@example.com # Extra configuration - - diff --git a/tests/modules/programs/neomutt/neomutt-with-imap-type-mailboxes-expected.conf b/tests/modules/programs/neomutt/neomutt-with-imap-type-mailboxes-expected.conf index 51c6c6b9f..5a7c5a645 100644 --- a/tests/modules/programs/neomutt/neomutt-with-imap-type-mailboxes-expected.conf +++ b/tests/modules/programs/neomutt/neomutt-with-imap-type-mailboxes-expected.conf @@ -4,34 +4,25 @@ set message_cachedir = "/home/hm-user/.cache/neomutt/messages/" set editor = "$EDITOR" set implicit_autoview = yes set crypt_use_gpgme = yes - alternative_order text/enriched text/plain text - set delete = yes - -# Binds - - # Macros - # Register accounts set account_command = '/nix/store/00000000000000000000000000000000-account-command.sh/bin/account-command.sh' -# register account hm@example.com + +## register account hm@example.com named-mailboxes "someCustomName" "/home/hm-user/Mail/hm@example.com/Inbox" mailboxes "/home/hm-user/Mail/hm@example.com/Sent" named-mailboxes "Spam" "imaps://home.manager@imap.example.com:993/Junk Email" mailboxes "/home/hm-user/Mail/hm@example.com/Trash" folder-hook /home/hm-user/Mail/hm@example.com/ " \ - source /home/hm-user/.config/neomutt/hm@example.com " - + source /home/hm-user/.config/neomutt/hm@example.com " # Source primary account source /home/hm-user/.config/neomutt/hm@example.com # Extra configuration - - diff --git a/tests/modules/programs/neomutt/neomutt-with-named-mailboxes-expected.conf b/tests/modules/programs/neomutt/neomutt-with-named-mailboxes-expected.conf index 605b5ed6d..cb2585f32 100644 --- a/tests/modules/programs/neomutt/neomutt-with-named-mailboxes-expected.conf +++ b/tests/modules/programs/neomutt/neomutt-with-named-mailboxes-expected.conf @@ -4,33 +4,24 @@ set message_cachedir = "/home/hm-user/.cache/neomutt/messages/" set editor = "$EDITOR" set implicit_autoview = yes set crypt_use_gpgme = yes - alternative_order text/enriched text/plain text - set delete = yes - -# Binds - - # Macros - # Register accounts -# register account hm@example.com + +## register account hm@example.com named-mailboxes "someCustomName" "/home/hm-user/Mail/hm@example.com/Inbox" mailboxes "/home/hm-user/Mail/hm@example.com/Sent" named-mailboxes "Spam" "/home/hm-user/Mail/hm@example.com/Junk Email" mailboxes "/home/hm-user/Mail/hm@example.com/Trash" folder-hook /home/hm-user/Mail/hm@example.com/ " \ - source /home/hm-user/.config/neomutt/hm@example.com " - + source /home/hm-user/.config/neomutt/hm@example.com " # Source primary account source /home/hm-user/.config/neomutt/hm@example.com # Extra configuration - - diff --git a/tests/modules/programs/neomutt/neomutt-with-named-mailboxes.nix b/tests/modules/programs/neomutt/neomutt-with-named-mailboxes.nix index 1d1d2fa47..bbd3afb5a 100644 --- a/tests/modules/programs/neomutt/neomutt-with-named-mailboxes.nix +++ b/tests/modules/programs/neomutt/neomutt-with-named-mailboxes.nix @@ -31,7 +31,7 @@ nmt.script = '' assertFileExists home-files/.config/neomutt/neomuttrc assertFileExists home-files/.config/neomutt/hm@example.com - assertFileContent home-files/.config/neomutt/neomuttrc ${ + assertFileContent $(normalizeStorePaths home-files/.config/neomutt/neomuttrc) ${ ./neomutt-with-named-mailboxes-expected.conf } assertFileContent home-files/.config/neomutt/hm@example.com ${ diff --git a/tests/modules/programs/neomutt/neomutt-with-signature.nix b/tests/modules/programs/neomutt/neomutt-with-signature.nix index e8361e0a2..347db9a3d 100644 --- a/tests/modules/programs/neomutt/neomutt-with-signature.nix +++ b/tests/modules/programs/neomutt/neomutt-with-signature.nix @@ -29,7 +29,7 @@ nmt.script = '' assertFileExists home-files/.config/neomutt/neomuttrc assertFileExists home-files/.config/neomutt/hm@example.com - assertFileContent home-files/.config/neomutt/neomuttrc ${ + assertFileContent $(normalizeStorePaths home-files/.config/neomutt/neomuttrc) ${ ./neomutt-expected.conf } expectedSignature=$(normalizeStorePaths "home-files/.config/neomutt/hm@example.com") diff --git a/tests/modules/programs/neovim/plugin-config.nix b/tests/modules/programs/neovim/plugin-config.nix index 0e014bc79..4b8c3abdc 100644 --- a/tests/modules/programs/neovim/plugin-config.nix +++ b/tests/modules/programs/neovim/plugin-config.nix @@ -15,7 +15,7 @@ lib.mkIf config.test.enableBig { ''; } ]; - extraLuaPackages = [ pkgs.lua51Packages.luautf8 ]; + extraLuaPackages = ps: [ ps.luautf8 ]; }; _module.args.pkgs = lib.mkForce realPkgs; diff --git a/tests/modules/programs/neovim/runtime.nix b/tests/modules/programs/neovim/runtime.nix index 61ec8b9b6..088f75ace 100644 --- a/tests/modules/programs/neovim/runtime.nix +++ b/tests/modules/programs/neovim/runtime.nix @@ -34,8 +34,8 @@ lib.mkIf config.test.enableBig { extraLuaPackages = ps: with ps; [ luacheck ]; } { - extraPython3Packages = with pkgs.python3Packages; [ jedi pynvim ]; - extraLuaPackages = with pkgs.lua51Packages; [ luacheck ]; + extraPython3Packages = ps: with ps; [ jedi pynvim ]; + extraLuaPackages = ps: with ps; [ luacheck ]; } ]; diff --git a/tests/modules/programs/nushell/example-settings.nix b/tests/modules/programs/nushell/example-settings.nix index f93dd8ed4..cc9e8f8ec 100644 --- a/tests/modules/programs/nushell/example-settings.nix +++ b/tests/modules/programs/nushell/example-settings.nix @@ -1,7 +1,6 @@ { pkgs, realPkgs, config, lib, ... }: -# Temporarily broken due to Nixpkgs issue. -lib.mkIf false { +{ programs.nushell = { enable = true; package = realPkgs.nushell; diff --git a/tests/modules/programs/onlyoffice/default.nix b/tests/modules/programs/onlyoffice/default.nix new file mode 100644 index 000000000..462e82b67 --- /dev/null +++ b/tests/modules/programs/onlyoffice/default.nix @@ -0,0 +1 @@ +{ onlyoffice-example-config = ./example-config.nix; } diff --git a/tests/modules/programs/onlyoffice/example-config.conf b/tests/modules/programs/onlyoffice/example-config.conf new file mode 100644 index 000000000..792c65047 --- /dev/null +++ b/tests/modules/programs/onlyoffice/example-config.conf @@ -0,0 +1,7 @@ +UITheme=theme-contrast-dark +editorWindowMode=false +forcedRtl=false +locale=es-ES +maximized=true +position=@Rect(100 56 1266 668) +titlebar=custom diff --git a/tests/modules/programs/onlyoffice/example-config.nix b/tests/modules/programs/onlyoffice/example-config.nix new file mode 100644 index 000000000..c9f010435 --- /dev/null +++ b/tests/modules/programs/onlyoffice/example-config.nix @@ -0,0 +1,20 @@ +{ + programs.onlyoffice = { + enable = true; + settings = { + UITheme = "theme-contrast-dark"; + editorWindowMode = false; + forcedRtl = false; + locale = "es-ES"; + maximized = true; + position = "@Rect(100 56 1266 668)"; + titlebar = "custom"; + }; + }; + + nmt.script = '' + assertFileExists home-files/.config/onlyoffice/DesktopEditors.conf + assertFileContent home-files/.config/onlyoffice/DesktopEditors.conf \ + ${./example-config.conf} + ''; +} diff --git a/tests/modules/programs/readline/prefer-xdg-dirs.nix b/tests/modules/programs/readline/prefer-xdg-dirs.nix index 869b8a2cb..b825b3bc2 100644 --- a/tests/modules/programs/readline/prefer-xdg-dirs.nix +++ b/tests/modules/programs/readline/prefer-xdg-dirs.nix @@ -1,5 +1,3 @@ -{ ... }: - { home.preferXdgDirectories = true; diff --git a/tests/modules/programs/readline/using-all-options.nix b/tests/modules/programs/readline/using-all-options.nix index 85c9fc140..a2ae4fafb 100644 --- a/tests/modules/programs/readline/using-all-options.nix +++ b/tests/modules/programs/readline/using-all-options.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.readline = { diff --git a/tests/modules/programs/ripgrep-all/custom-arguments.nix b/tests/modules/programs/ripgrep-all/custom-arguments.nix new file mode 100644 index 000000000..01ee70db7 --- /dev/null +++ b/tests/modules/programs/ripgrep-all/custom-arguments.nix @@ -0,0 +1,51 @@ +{ pkgs, config, ... }: { + config = { + programs.ripgrep-all = { + enable = true; + package = config.lib.test.mkStubPackage { name = "ripgrep-all"; }; + custom_adapters = [{ + name = "gron"; + version = 1; + description = "Transform JSON into discrete JS assignments"; + extensions = [ "json" ]; + mimetypes = [ "application/json" ]; + binary = "/bin/gron"; + disabled_by_default = false; + match_only_by_mime = false; + }]; + }; + + nmt.script = let + configPath = if pkgs.stdenv.hostPlatform.isDarwin then + "Library/Application Support/ripgrep-all/config.jsonc" + else + ".config/ripgrep-all/config.jsonc"; + in '' + assertFileExists "home-files/${configPath}" + assertFileContent "home-files/${configPath}" ${ + pkgs.writeText "ripgrep-all.expected" '' + { + "$schema": "./config.schema.json", + "custom_adapters": [ + { + "args": [], + "binary": "/bin/gron", + "description": "Transform JSON into discrete JS assignments", + "disabled_by_default": false, + "extensions": [ + "json" + ], + "match_only_by_mime": false, + "mimetypes": [ + "application/json" + ], + "name": "gron", + "version": 1 + } + ] + } + '' + } + ''; + }; +} diff --git a/tests/modules/programs/ripgrep-all/default-arguments.nix b/tests/modules/programs/ripgrep-all/default-arguments.nix new file mode 100644 index 000000000..61ba46b62 --- /dev/null +++ b/tests/modules/programs/ripgrep-all/default-arguments.nix @@ -0,0 +1,13 @@ +{ config, ... }: { + config = { + programs.ripgrep-all = { + enable = true; + package = config.lib.test.mkStubPackage { name = "ripgrep-all"; }; + }; + + nmt.script = '' + assertPathNotExists home-files/.config/ripgrep-all/config.jsonc + assertPathNotExists 'home-files/Library/Application Support/ripgrep-all/config.jsonc' + ''; + }; +} diff --git a/tests/modules/programs/ripgrep-all/default.nix b/tests/modules/programs/ripgrep-all/default.nix new file mode 100644 index 000000000..ddc31c28b --- /dev/null +++ b/tests/modules/programs/ripgrep-all/default.nix @@ -0,0 +1,4 @@ +{ + ripgrep-all-default-arguments = ./default-arguments.nix; + ripgrep-all-custom-arguments = ./custom-arguments.nix; +} diff --git a/tests/modules/programs/ssh/default-config.nix b/tests/modules/programs/ssh/default-config.nix index 6d7e5508a..60a966130 100644 --- a/tests/modules/programs/ssh/default-config.nix +++ b/tests/modules/programs/ssh/default-config.nix @@ -1,13 +1,9 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, lib, ... }: { config = { programs.ssh = { enable = true; }; home.file.assertions.text = builtins.toJSON - (map (a: a.message) (filter (a: !a.assertion) config.assertions)); + (map (a: a.message) (lib.filter (a: !a.assertion) config.assertions)); nmt.script = '' assertFileExists home-files/.ssh/config diff --git a/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix b/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix index e841b5bcd..ce83b2c13 100644 --- a/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix +++ b/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.ssh = { diff --git a/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix b/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix index d0c3a7322..ae5c1fb9e 100644 --- a/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix +++ b/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, lib, ... }: { config = { programs.ssh = { enable = true; @@ -25,7 +21,7 @@ with lib; }; home.file.result.text = builtins.toJSON - (map (a: a.message) (filter (a: !a.assertion) config.assertions)); + (map (a: a.message) (lib.filter (a: !a.assertion) config.assertions)); nmt.script = '' assertFileExists home-files/.ssh/config diff --git a/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix b/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix index e7ac454e8..0c05bb108 100644 --- a/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix +++ b/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.ssh = { diff --git a/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix b/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix index 890459c8a..9dca55abb 100644 --- a/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix +++ b/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.ssh = { diff --git a/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix b/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix index ece7d7953..645876078 100644 --- a/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix +++ b/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.ssh = { diff --git a/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix b/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix index b1228f4ef..c4f549e21 100644 --- a/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix +++ b/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.ssh = { diff --git a/tests/modules/programs/ssh/match-blocks-attrs.nix b/tests/modules/programs/ssh/match-blocks-attrs.nix index d8584e3a0..21deb7e27 100644 --- a/tests/modules/programs/ssh/match-blocks-attrs.nix +++ b/tests/modules/programs/ssh/match-blocks-attrs.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, lib, ... }: { config = { programs.ssh = { enable = true; @@ -12,7 +8,7 @@ with lib; proxyJump = "jump-host"; }; - ordered = hm.dag.entryAfter [ "xyz" ] { port = 1; }; + ordered = lib.hm.dag.entryAfter [ "xyz" ] { port = 1; }; xyz = { identityFile = "file"; @@ -49,7 +45,7 @@ with lib; }; home.file.assertions.text = builtins.toJSON - (map (a: a.message) (filter (a: !a.assertion) config.assertions)); + (map (a: a.message) (lib.filter (a: !a.assertion) config.assertions)); nmt.script = '' assertFileExists home-files/.ssh/config diff --git a/tests/modules/programs/ssh/match-blocks-match-and-hosts.nix b/tests/modules/programs/ssh/match-blocks-match-and-hosts.nix index aa1e40d05..01e91c0b6 100644 --- a/tests/modules/programs/ssh/match-blocks-match-and-hosts.nix +++ b/tests/modules/programs/ssh/match-blocks-match-and-hosts.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, lib, ... }: { config = { programs.ssh = { enable = true; @@ -19,7 +15,7 @@ with lib; }; home.file.assertions.text = builtins.toJSON - (map (a: a.message) (filter (a: !a.assertion) config.assertions)); + (map (a: a.message) (lib.filter (a: !a.assertion) config.assertions)); nmt.script = '' assertFileExists home-files/.ssh/config diff --git a/tests/modules/programs/swayimg/default.nix b/tests/modules/programs/swayimg/default.nix new file mode 100644 index 000000000..b2c3dfa9b --- /dev/null +++ b/tests/modules/programs/swayimg/default.nix @@ -0,0 +1,4 @@ +{ + swayimg-empty-settings = ./empty-settings.nix; + swayimg-example-settings = ./example-settings.nix; +} diff --git a/tests/modules/programs/swayimg/empty-settings.nix b/tests/modules/programs/swayimg/empty-settings.nix new file mode 100644 index 000000000..3ea1c2347 --- /dev/null +++ b/tests/modules/programs/swayimg/empty-settings.nix @@ -0,0 +1,7 @@ +{ + programs.swayimg.enable = true; + + nmt.script = '' + assertPathNotExists home-files/.config/swayimg + ''; +} diff --git a/tests/modules/programs/swayimg/example-settings-expected.ini b/tests/modules/programs/swayimg/example-settings-expected.ini new file mode 100644 index 000000000..f844feb6c --- /dev/null +++ b/tests/modules/programs/swayimg/example-settings-expected.ini @@ -0,0 +1,9 @@ +[info.viewer] +top_left=+name,+format + +[keys.viewer] +Shift+r=rand_file + +[viewer] +scale=fill +window=#10000010 diff --git a/tests/modules/programs/swayimg/example-settings.nix b/tests/modules/programs/swayimg/example-settings.nix new file mode 100644 index 000000000..a1c4adfd2 --- /dev/null +++ b/tests/modules/programs/swayimg/example-settings.nix @@ -0,0 +1,23 @@ +{ config, ... }: + +{ + programs.swayimg = { + enable = true; + package = config.lib.test.mkStubPackage { }; + + settings = { + viewer = { + window = "#10000010"; + scale = "fill"; + }; + "info.viewer" = { top_left = "+name,+format"; }; + "keys.viewer" = { "Shift+r" = "rand_file"; }; + }; + }; + + nmt.script = '' + assertFileContent \ + home-files/.config/swayimg/config \ + ${./example-settings-expected.ini} + ''; +} diff --git a/tests/modules/programs/tex-fmt/custom-settings.nix b/tests/modules/programs/tex-fmt/custom-settings.nix new file mode 100644 index 000000000..a4123b095 --- /dev/null +++ b/tests/modules/programs/tex-fmt/custom-settings.nix @@ -0,0 +1,31 @@ +{ config, pkgs, ... }: { + config = { + programs.tex-fmt = { + enable = true; + settings = { + wrap = true; + tabsize = 2; + tabchar = "space"; + lists = [ ]; + }; + }; + + nmt.script = let + expectedConfDir = if pkgs.stdenv.isDarwin then + "Library/Application Support" + else + ".config"; + expectedConfigPath = "home-files/${expectedConfDir}/tex-fmt/tex-fmt.toml"; + in '' + assertFileExists "${expectedConfigPath}" + assertFileContent "${expectedConfigPath}" ${ + pkgs.writeText "tex-fmt.config-custom.expected" '' + lists = [] + tabchar = "space" + tabsize = 2 + wrap = true + '' + } + ''; + }; +} diff --git a/tests/modules/programs/tex-fmt/default-settings.nix b/tests/modules/programs/tex-fmt/default-settings.nix new file mode 100644 index 000000000..427493946 --- /dev/null +++ b/tests/modules/programs/tex-fmt/default-settings.nix @@ -0,0 +1,15 @@ +{ config, pkgs, ... }: { + config = { + programs.tex-fmt = { enable = true; }; + + nmt.script = let + expectedConfDir = if pkgs.stdenv.isDarwin then + "Library/Application Support" + else + ".config"; + expectedConfigPath = "home-files/${expectedConfDir}/tex-fmt/tex-fmt.toml"; + in '' + assertPathNotExists "${expectedConfigPath}" + ''; + }; +} diff --git a/tests/modules/programs/tex-fmt/default.nix b/tests/modules/programs/tex-fmt/default.nix new file mode 100644 index 000000000..e75a8b354 --- /dev/null +++ b/tests/modules/programs/tex-fmt/default.nix @@ -0,0 +1,4 @@ +{ + tex-fmt-default-settings = ./default-settings.nix; + tex-fmt-custom-settings = ./custom-settings.nix; +} diff --git a/tests/modules/programs/texlive/texlive-minimal.nix b/tests/modules/programs/texlive/texlive-minimal.nix index 1b13936be..8db048e58 100644 --- a/tests/modules/programs/texlive/texlive-minimal.nix +++ b/tests/modules/programs/texlive/texlive-minimal.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ lib, pkgs, ... }: { config = { programs.texlive.enable = true; @@ -14,7 +10,7 @@ with lib; combine = tpkgs: pkgs.symlinkJoin { name = "dummy-texlive-combine"; - paths = attrValues tpkgs; + paths = lib.attrValues tpkgs; }; }; }) diff --git a/tests/modules/programs/thunderbird/default.nix b/tests/modules/programs/thunderbird/default.nix index 487297784..0fddeec16 100644 --- a/tests/modules/programs/thunderbird/default.nix +++ b/tests/modules/programs/thunderbird/default.nix @@ -1 +1,5 @@ -{ thunderbird = ./thunderbird.nix; } +{ + thunderbird = ./thunderbird.nix; + thunderbird-with-firefox = ./thunderbird-with-firefox.nix; + thunderbird-native-messaging-host = ./thunderbird-native-messaging-host.nix; +} diff --git a/tests/modules/programs/thunderbird/thunderbird-expected-first-darwin.js b/tests/modules/programs/thunderbird/thunderbird-expected-first-darwin.js index 34f7f4eff..2fe2fa39f 100644 --- a/tests/modules/programs/thunderbird/thunderbird-expected-first-darwin.js +++ b/tests/modules/programs/thunderbird/thunderbird-expected-first-darwin.js @@ -3,9 +3,10 @@ user_pref("general.useragent.override", ""); user_pref("mail.account.account_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc.identities", "id_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc"); user_pref("mail.account.account_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc.server", "server_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc"); +user_pref("mail.account.account_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.server", "server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab"); user_pref("mail.account.account_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f.identities", "id_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f,id_8bbcff78f53202c0bfaa490a2068e3e5d6e36872144c659952ecc0ada47d7562"); user_pref("mail.account.account_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f.server", "server_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f"); -user_pref("mail.accountmanager.accounts", "account_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc,account_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f"); +user_pref("mail.accountmanager.accounts", "account_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc,account_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f,account_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab"); user_pref("mail.accountmanager.defaultaccount", "account_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f"); user_pref("mail.identity.id_8bbcff78f53202c0bfaa490a2068e3e5d6e36872144c659952ecc0ada47d7562.attachPgpKey", false); user_pref("mail.identity.id_8bbcff78f53202c0bfaa490a2068e3e5d6e36872144c659952ecc0ada47d7562.autoEncryptDrafts", true); @@ -52,6 +53,11 @@ user_pref("mail.server.server_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da50 user_pref("mail.server.server_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc.socketType", 3); user_pref("mail.server.server_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc.type", "imap"); user_pref("mail.server.server_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc.userName", "home.manager.jr"); +user_pref("mail.server.server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.directory", "Library/Thunderbird/Profiles/first/Mail/Feeds-c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab"); +user_pref("mail.server.server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.directory-rel", "[ProfD]Mail/Feeds-c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab"); +user_pref("mail.server.server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.hostname", "Feeds-c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab"); +user_pref("mail.server.server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.name", "rss"); +user_pref("mail.server.server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.type", "rss"); user_pref("mail.server.server_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f.directory", "Library/Thunderbird/Profiles/first/ImapMail/cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f"); user_pref("mail.server.server_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f.directory-rel", "[ProfD]ImapMail/cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f"); user_pref("mail.server.server_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f.hostname", "imap.example.com"); diff --git a/tests/modules/programs/thunderbird/thunderbird-expected-first-linux.js b/tests/modules/programs/thunderbird/thunderbird-expected-first-linux.js index 8499ef89e..6d5f57274 100644 --- a/tests/modules/programs/thunderbird/thunderbird-expected-first-linux.js +++ b/tests/modules/programs/thunderbird/thunderbird-expected-first-linux.js @@ -3,9 +3,10 @@ user_pref("general.useragent.override", ""); user_pref("mail.account.account_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc.identities", "id_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc"); user_pref("mail.account.account_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc.server", "server_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc"); +user_pref("mail.account.account_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.server", "server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab"); user_pref("mail.account.account_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f.identities", "id_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f,id_8bbcff78f53202c0bfaa490a2068e3e5d6e36872144c659952ecc0ada47d7562"); user_pref("mail.account.account_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f.server", "server_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f"); -user_pref("mail.accountmanager.accounts", "account_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc,account_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f"); +user_pref("mail.accountmanager.accounts", "account_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc,account_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f,account_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab"); user_pref("mail.accountmanager.defaultaccount", "account_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f"); user_pref("mail.identity.id_8bbcff78f53202c0bfaa490a2068e3e5d6e36872144c659952ecc0ada47d7562.attachPgpKey", false); user_pref("mail.identity.id_8bbcff78f53202c0bfaa490a2068e3e5d6e36872144c659952ecc0ada47d7562.autoEncryptDrafts", true); @@ -52,6 +53,11 @@ user_pref("mail.server.server_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da50 user_pref("mail.server.server_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc.socketType", 3); user_pref("mail.server.server_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc.type", "imap"); user_pref("mail.server.server_bcd3ace52bed41febb6cdc2fb1303aebaa573e0d993872da503950901bb6c6fc.userName", "home.manager.jr"); +user_pref("mail.server.server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.directory", ".thunderbird/first/Mail/Feeds-c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab"); +user_pref("mail.server.server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.directory-rel", "[ProfD]Mail/Feeds-c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab"); +user_pref("mail.server.server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.hostname", "Feeds-c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab"); +user_pref("mail.server.server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.name", "rss"); +user_pref("mail.server.server_c6cc42837ed0a8041f93ff12c579a4af0dbe702461c97eef069f9f5f8dc4bfab.type", "rss"); user_pref("mail.server.server_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f.directory", ".thunderbird/first/ImapMail/cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f"); user_pref("mail.server.server_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f.directory-rel", "[ProfD]ImapMail/cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f"); user_pref("mail.server.server_cda3f13b64c1db7d4b58ce07a31304a362d7dcaf14476bfabcca913ae41ada9f.hostname", "imap.example.com"); diff --git a/tests/modules/programs/thunderbird/thunderbird-expected-msgFilterRules.dat b/tests/modules/programs/thunderbird/thunderbird-expected-msgFilterRules.dat new file mode 100644 index 000000000..8b810a0da --- /dev/null +++ b/tests/modules/programs/thunderbird/thunderbird-expected-msgFilterRules.dat @@ -0,0 +1,12 @@ +version="9" +logging="no" +name="Should be first" +enabled="yes" +type="128" +action="Cry" +condition="ALL" +name="Mark as Read on Archive" +enabled="yes" +type="128" +action="Mark read" +condition="ALL" diff --git a/tests/modules/programs/thunderbird/thunderbird-native-messaging-host.nix b/tests/modules/programs/thunderbird/thunderbird-native-messaging-host.nix new file mode 100644 index 000000000..57bef0f13 --- /dev/null +++ b/tests/modules/programs/thunderbird/thunderbird-native-messaging-host.nix @@ -0,0 +1,25 @@ +# Confirm that both Firefox and Thunderbird can be configured at the same time. +{ lib, realPkgs, ... }: +lib.recursiveUpdate (import ./thunderbird.nix { inherit lib realPkgs; }) { + programs.thunderbird = { + nativeMessagingHosts = with realPkgs; + [ + # NOTE: this is not a real Thunderbird native host module but Firefox; no + # native hosts are currently packaged for nixpkgs or elsewhere, so we + # have to improvise. Packaging wise, Firefox and Thunderbird native hosts + # are identical though. The test doesn't care if the host was meant for + # either as long as the right paths are present in the package. + browserpass + ]; + }; + + nmt.script = let + isDarwin = realPkgs.stdenv.hostPlatform.isDarwin; + nativeHostsDir = if isDarwin then + "Library/Mozilla/NativeMessagingHosts" + else + ".mozilla/native-messaging-hosts"; + in '' + assertFileExists home-files/${nativeHostsDir}/com.github.browserpass.native.json + ''; +} diff --git a/tests/modules/programs/thunderbird/thunderbird-with-firefox.nix b/tests/modules/programs/thunderbird/thunderbird-with-firefox.nix new file mode 100644 index 000000000..0d23460d2 --- /dev/null +++ b/tests/modules/programs/thunderbird/thunderbird-with-firefox.nix @@ -0,0 +1,9 @@ +# Confirm that both Firefox and Thunderbird can be configured at the same time. +{ lib, realPkgs, ... }: +lib.recursiveUpdate (import ./thunderbird.nix { inherit lib realPkgs; }) { + programs.firefox = { + enable = true; + # Darwin doesn't support wrapped Firefox, using unwrapped instead + package = realPkgs.firefox-unwrapped; + }; +} diff --git a/tests/modules/programs/thunderbird/thunderbird.nix b/tests/modules/programs/thunderbird/thunderbird.nix index 4526d6686..35e87d452 100644 --- a/tests/modules/programs/thunderbird/thunderbird.nix +++ b/tests/modules/programs/thunderbird/thunderbird.nix @@ -1,4 +1,4 @@ -{ pkgs, ... }: { +{ lib, realPkgs, ... }: { imports = [ ../../accounts/email-test-accounts.nix ]; accounts.email.accounts = { @@ -6,6 +6,22 @@ thunderbird = { enable = true; profiles = [ "first" ]; + messageFilters = [ + { + name = "Should be first"; + enabled = true; + type = "128"; + action = "Cry"; + condition = "ALL"; + } + { + name = "Mark as Read on Archive"; + enabled = true; + type = "128"; + action = "Mark read"; + condition = "ALL"; + } + ]; }; aliases = [ "home-manager@example.com" ]; @@ -41,6 +57,10 @@ # Disable warning so that platforms' behavior is the same darwinSetupWarning = false; + # Darwin doesn't support wrapped Thunderbird, using unwrapped instead; + # using -latest- because ESR is currently broken on Darwin + package = realPkgs.thunderbird-latest-unwrapped; + profiles = { first = { isDefault = true; @@ -54,6 +74,8 @@ extraConfig = '' user_pref("mail.html_compose", false); ''; + + feedAccounts.rss = { }; }; second.settings = { @@ -69,7 +91,7 @@ }; nmt.script = let - isDarwin = pkgs.stdenv.hostPlatform.isDarwin; + isDarwin = realPkgs.stdenv.hostPlatform.isDarwin; configDir = if isDarwin then "Library/Thunderbird" else ".thunderbird"; profilesDir = if isDarwin then "${configDir}/Profiles" else "${configDir}"; platform = if isDarwin then "darwin" else "linux"; @@ -93,5 +115,13 @@ assertFileExists home-files/${profilesDir}/first/chrome/userContent.css assertFileContent home-files/${profilesDir}/first/chrome/userContent.css \ <(echo "* { color: red !important; }") + + assertFileExists home-files/${profilesDir}/first/ImapMail/${ + builtins.hashString "sha256" "hm@example.com" + }/msgFilterRules.dat + assertFileContent home-files/${profilesDir}/first/ImapMail/${ + builtins.hashString "sha256" "hm@example.com" + }/msgFilterRules.dat \ + ${./thunderbird-expected-msgFilterRules.dat} ''; } diff --git a/tests/modules/programs/tmux/default-shell.nix b/tests/modules/programs/tmux/default-shell.nix index af05eb0e7..f0718b8ad 100644 --- a/tests/modules/programs/tmux/default-shell.nix +++ b/tests/modules/programs/tmux/default-shell.nix @@ -1,7 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - +{ pkgs, ... }: let substituteExpected = path: diff --git a/tests/modules/programs/tmux/disable-confirmation-prompt.nix b/tests/modules/programs/tmux/disable-confirmation-prompt.nix index aec1f66cf..7bcc08e16 100644 --- a/tests/modules/programs/tmux/disable-confirmation-prompt.nix +++ b/tests/modules/programs/tmux/disable-confirmation-prompt.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.tmux = { diff --git a/tests/modules/programs/tmux/emacs-with-plugins.nix b/tests/modules/programs/tmux/emacs-with-plugins.nix index 4a0382d8d..146c5fa8e 100644 --- a/tests/modules/programs/tmux/emacs-with-plugins.nix +++ b/tests/modules/programs/tmux/emacs-with-plugins.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ pkgs, ... }: { config = { programs.tmux = { aggressiveResize = true; diff --git a/tests/modules/programs/tmux/mouse-enabled.nix b/tests/modules/programs/tmux/mouse-enabled.nix index 6fc5b526e..5e674e21c 100644 --- a/tests/modules/programs/tmux/mouse-enabled.nix +++ b/tests/modules/programs/tmux/mouse-enabled.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.tmux = { diff --git a/tests/modules/programs/tmux/not-enabled.nix b/tests/modules/programs/tmux/not-enabled.nix index d5f08b36f..556aaef9e 100644 --- a/tests/modules/programs/tmux/not-enabled.nix +++ b/tests/modules/programs/tmux/not-enabled.nix @@ -1,7 +1,3 @@ -{ config, lib, ... }: - -with lib; - { config = { programs.tmux = { enable = false; }; diff --git a/tests/modules/programs/tmux/prefix.nix b/tests/modules/programs/tmux/prefix.nix index 9f97940e7..7777ad6df 100644 --- a/tests/modules/programs/tmux/prefix.nix +++ b/tests/modules/programs/tmux/prefix.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.tmux = { diff --git a/tests/modules/programs/tmux/secure-socket-enabled.nix b/tests/modules/programs/tmux/secure-socket-enabled.nix index 60b3f7087..eeb708f7c 100644 --- a/tests/modules/programs/tmux/secure-socket-enabled.nix +++ b/tests/modules/programs/tmux/secure-socket-enabled.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.tmux = { diff --git a/tests/modules/programs/tmux/shortcut-without-prefix.nix b/tests/modules/programs/tmux/shortcut-without-prefix.nix index 5c294ef97..635a9e10b 100644 --- a/tests/modules/programs/tmux/shortcut-without-prefix.nix +++ b/tests/modules/programs/tmux/shortcut-without-prefix.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.tmux = { diff --git a/tests/modules/programs/tmux/vi-all-true.nix b/tests/modules/programs/tmux/vi-all-true.nix index 8b9cf1a36..e04ea922e 100644 --- a/tests/modules/programs/tmux/vi-all-true.nix +++ b/tests/modules/programs/tmux/vi-all-true.nix @@ -1,7 +1,3 @@ -{ config, lib, pkgs, ... }: - -with lib; - { config = { programs.tmux = { diff --git a/tests/modules/programs/vinegar/default.nix b/tests/modules/programs/vinegar/default.nix new file mode 100644 index 000000000..0916c04ae --- /dev/null +++ b/tests/modules/programs/vinegar/default.nix @@ -0,0 +1,4 @@ +{ + vinegar-empty-settings = ./empty-settings.nix; + vinegar-example-settings = ./example-settings.nix; +} diff --git a/tests/modules/programs/vinegar/empty-settings.nix b/tests/modules/programs/vinegar/empty-settings.nix new file mode 100644 index 000000000..e7a480036 --- /dev/null +++ b/tests/modules/programs/vinegar/empty-settings.nix @@ -0,0 +1,7 @@ +{ + programs.vinegar.enable = true; + + nmt.script = '' + assertPathNotExists home-files/.config/vinegar/config.toml + ''; +} diff --git a/tests/modules/programs/vinegar/example-config-expected.toml b/tests/modules/programs/vinegar/example-config-expected.toml new file mode 100644 index 000000000..38878ce1c --- /dev/null +++ b/tests/modules/programs/vinegar/example-config-expected.toml @@ -0,0 +1,13 @@ +[env] +WINEFSYNC = "1" + +[studio] +dxvk = false +renderer = "Vulkan" + +[studio.env] +DXVK_HUD = "0" +MANGOHUD = "1" + +[studio.fflags] +DFIntTaskSchedulerTargetFps = 144 diff --git a/tests/modules/programs/vinegar/example-settings.nix b/tests/modules/programs/vinegar/example-settings.nix new file mode 100644 index 000000000..22ac75df5 --- /dev/null +++ b/tests/modules/programs/vinegar/example-settings.nix @@ -0,0 +1,28 @@ +{ config, ... }: { + programs.vinegar = { + enable = true; + package = config.lib.test.mkStubPackage { }; + + settings = { + env.WINEFSYNC = "1"; + + studio = { + dxvk = false; + renderer = "Vulkan"; + + fflags.DFIntTaskSchedulerTargetFps = 144; + + env = { + DXVK_HUD = "0"; + MANGOHUD = "1"; + }; + }; + }; + }; + + nmt.script = '' + assertFileContent \ + home-files/.config/vinegar/config.toml \ + ${./example-config-expected.toml} + ''; +} diff --git a/tests/modules/programs/vscode/keybindings.nix b/tests/modules/programs/vscode/keybindings.nix index 64212e29a..a0d3ea93f 100644 --- a/tests/modules/programs/vscode/keybindings.nix +++ b/tests/modules/programs/vscode/keybindings.nix @@ -1,5 +1,5 @@ # Test that keybindings.json is created correctly. -{ pkgs, ... }: +{ pkgs, lib, ... }: let bindings = [ @@ -25,15 +25,25 @@ let } ]; - keybindingsPath = if pkgs.stdenv.hostPlatform.isDarwin then - "Library/Application Support/Code/User/keybindings.json" - else - ".config/Code/User/keybindings.json"; + keybindingsPath = name: + if pkgs.stdenv.hostPlatform.isDarwin then + "Library/Application Support/Code/User/${ + lib.optionalString (name != "default") "profiles/${name}/" + }keybindings.json" + else + ".config/Code/User/${ + lib.optionalString (name != "default") "profiles/${name}/" + }keybindings.json"; - settingsPath = if pkgs.stdenv.hostPlatform.isDarwin then - "Library/Application Support/Code/User/settings.json" - else - ".config/Code/User/settings.json"; + settingsPath = name: + if pkgs.stdenv.hostPlatform.isDarwin then + "Library/Application Support/Code/User/${ + lib.optionalString (name != "default") "profiles/${name}/" + }settings.json" + else + ".config/Code/User/${ + lib.optionalString (name != "default") "profiles/${name}/" + }settings.json"; expectedKeybindings = pkgs.writeText "expected.json" '' [ @@ -65,14 +75,29 @@ let in { programs.vscode = { enable = true; - keybindings = bindings; - package = pkgs.writeScriptBin "vscode" "" // { pname = "vscode"; }; + profiles = { + default.keybindings = bindings; + test.keybindings = bindings; + }; + package = pkgs.writeScriptBin "vscode" "" // { + pname = "vscode"; + version = "1.75.0"; + }; }; nmt.script = '' - assertFileExists "home-files/${keybindingsPath}" - assertFileContent "home-files/${keybindingsPath}" "${expectedKeybindings}" + assertFileExists "home-files/${keybindingsPath "default"}" + assertFileContent "home-files/${ + keybindingsPath "default" + }" "${expectedKeybindings}" - assertPathNotExists "home-files/${settingsPath}" + assertPathNotExists "home-files/${settingsPath "default"}" + + assertFileExists "home-files/${keybindingsPath "test"}" + assertFileContent "home-files/${ + keybindingsPath "test" + }" "${expectedKeybindings}" + + assertPathNotExists "home-files/${settingsPath "test"}" ''; } diff --git a/tests/modules/programs/vscode/snippets.nix b/tests/modules/programs/vscode/snippets.nix index a7ea44f76..eafa69186 100644 --- a/tests/modules/programs/vscode/snippets.nix +++ b/tests/modules/programs/vscode/snippets.nix @@ -1,13 +1,18 @@ -{ pkgs, ... }: +{ pkgs, lib, ... }: let - snippetsDir = if pkgs.stdenv.hostPlatform.isDarwin then - "Library/Application Support/Code/User/snippets" - else - ".config/Code/User/snippets"; + snippetsDir = name: + if pkgs.stdenv.hostPlatform.isDarwin then + "Library/Application Support/Code/User/${ + lib.optionalString (name != "default") "profiles/${name}/" + }/snippets" + else + ".config/Code/User/${ + lib.optionalString (name != "default") "profiles/${name}/" + }snippets"; - globalSnippetsPath = "${snippetsDir}/global.code-snippets"; + globalSnippetsPath = name: "${snippetsDir name}/global.code-snippets"; globalSnippetsExpectedContent = pkgs.writeText "global.code-snippet" '' { @@ -23,7 +28,7 @@ let } ''; - haskellSnippetsPath = "${snippetsDir}/haskell.json"; + haskellSnippetsPath = name: "${snippetsDir name}/haskell.json"; haskellSnippetsExpectedContent = pkgs.writeText "haskell.json" '' { @@ -39,10 +44,7 @@ let } ''; -in { - programs.vscode = { - enable = true; - package = pkgs.writeScriptBin "vscode" "" // { pname = "vscode"; }; + snippets = { globalSnippets = { fixme = { prefix = [ "fixme" ]; @@ -61,11 +63,38 @@ in { }; }; - nmt.script = '' - assertFileExists "home-files/${globalSnippetsPath}" - assertFileContent "home-files/${globalSnippetsPath}" "${globalSnippetsExpectedContent}" +in { + programs.vscode = { + enable = true; + package = pkgs.writeScriptBin "vscode" "" // { + pname = "vscode"; + version = "1.75.0"; + }; + profiles = { + default = snippets; + test = snippets; + }; + }; - assertFileExists "home-files/${haskellSnippetsPath}" - assertFileContent "home-files/${haskellSnippetsPath}" "${haskellSnippetsExpectedContent}" + nmt.script = '' + assertFileExists "home-files/${globalSnippetsPath "default"}" + assertFileContent "home-files/${ + globalSnippetsPath "default" + }" "${globalSnippetsExpectedContent}" + + assertFileExists "home-files/${globalSnippetsPath "test"}" + assertFileContent "home-files/${ + globalSnippetsPath "test" + }" "${globalSnippetsExpectedContent}" + + assertFileExists "home-files/${haskellSnippetsPath "default"}" + assertFileContent "home-files/${ + haskellSnippetsPath "default" + }" "${haskellSnippetsExpectedContent}" + + assertFileExists "home-files/${haskellSnippetsPath "test"}" + assertFileContent "home-files/${ + haskellSnippetsPath "test" + }" "${haskellSnippetsExpectedContent}" ''; } diff --git a/tests/modules/programs/vscode/tasks.nix b/tests/modules/programs/vscode/tasks.nix index ea85b3d6c..f7b266a33 100644 --- a/tests/modules/programs/vscode/tasks.nix +++ b/tests/modules/programs/vscode/tasks.nix @@ -1,11 +1,16 @@ -{ pkgs, ... }: +{ pkgs, lib, ... }: let - tasksFilePath = if pkgs.stdenv.hostPlatform.isDarwin then - "Library/Application Support/Code/User/tasks.json" - else - ".config/Code/User/tasks.json"; + tasksFilePath = name: + if pkgs.stdenv.hostPlatform.isDarwin then + "Library/Application Support/Code/User/${ + lib.optionalString (name != "default") "profiles/${name}/" + }tasks.json" + else + ".config/Code/User/${ + lib.optionalString (name != "default") "profiles/${name}/" + }tasks.json"; tasks = { version = "2.0.0"; @@ -32,12 +37,21 @@ let in { programs.vscode = { enable = true; - package = pkgs.writeScriptBin "vscode" "" // { pname = "vscode"; }; - userTasks = tasks; + package = pkgs.writeScriptBin "vscode" "" // { + pname = "vscode"; + version = "1.75.0"; + }; + profiles = { + default.userTasks = tasks; + test.userTasks = tasks; + }; }; nmt.script = '' - assertFileExists "home-files/${tasksFilePath}" - assertFileContent "home-files/${tasksFilePath}" "${expectedTasks}" + assertFileExists "home-files/${tasksFilePath "default"}" + assertFileContent "home-files/${tasksFilePath "default"}" "${expectedTasks}" + + assertFileExists "home-files/${tasksFilePath "test"}" + assertFileContent "home-files/${tasksFilePath "test"}" "${expectedTasks}" ''; } diff --git a/tests/modules/programs/vscode/update-checks.nix b/tests/modules/programs/vscode/update-checks.nix index 1547bd36a..b75cda566 100644 --- a/tests/modules/programs/vscode/update-checks.nix +++ b/tests/modules/programs/vscode/update-checks.nix @@ -17,9 +17,14 @@ let in { programs.vscode = { enable = true; - package = pkgs.writeScriptBin "vscode" "" // { pname = "vscode"; }; - enableUpdateCheck = false; - enableExtensionUpdateCheck = false; + package = pkgs.writeScriptBin "vscode" "" // { + pname = "vscode"; + version = "1.75.0"; + }; + profiles.default = { + enableUpdateCheck = false; + enableExtensionUpdateCheck = false; + }; }; nmt.script = '' diff --git a/tests/modules/programs/watson/empty-settings.nix b/tests/modules/programs/watson/empty-settings.nix index 8e0474665..3dec3b76e 100644 --- a/tests/modules/programs/watson/empty-settings.nix +++ b/tests/modules/programs/watson/empty-settings.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, pkgs, ... }: { programs.watson = { enable = true; package = config.lib.test.mkStubPackage { }; diff --git a/tests/modules/programs/watson/example-settings.nix b/tests/modules/programs/watson/example-settings.nix index f81f1ac85..11fd988aa 100644 --- a/tests/modules/programs/watson/example-settings.nix +++ b/tests/modules/programs/watson/example-settings.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, pkgs, ... }: { programs.watson = { enable = true; package = config.lib.test.mkStubPackage { }; diff --git a/tests/modules/programs/waybar/systemd-with-graphical-session-target.service b/tests/modules/programs/waybar/systemd-with-graphical-session-target.service index f3e3b24a3..5056d1be4 100644 --- a/tests/modules/programs/waybar/systemd-with-graphical-session-target.service +++ b/tests/modules/programs/waybar/systemd-with-graphical-session-target.service @@ -1,4 +1,5 @@ [Install] +WantedBy=tray.target WantedBy=sway-session.target [Service] @@ -13,3 +14,4 @@ ConditionEnvironment=WAYLAND_DISPLAY Description=Highly customizable Wayland bar for Sway and Wlroots based compositors. Documentation=https://github.com/Alexays/Waybar/wiki PartOf=sway-session.target +PartOf=tray.target diff --git a/tests/modules/programs/wlogout/layout-multiple.nix b/tests/modules/programs/wlogout/layout-multiple.nix index 108961aae..8e7e06a80 100644 --- a/tests/modules/programs/wlogout/layout-multiple.nix +++ b/tests/modules/programs/wlogout/layout-multiple.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { config = { home.stateVersion = "22.11"; diff --git a/tests/modules/programs/wlogout/layout-single.nix b/tests/modules/programs/wlogout/layout-single.nix index bbb5d61e6..9bcac8211 100644 --- a/tests/modules/programs/wlogout/layout-single.nix +++ b/tests/modules/programs/wlogout/layout-single.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { config = { home.stateVersion = "22.11"; diff --git a/tests/modules/programs/wlogout/styling.nix b/tests/modules/programs/wlogout/styling.nix index 6df6290fd..8233d25b6 100644 --- a/tests/modules/programs/wlogout/styling.nix +++ b/tests/modules/programs/wlogout/styling.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { config = { home.stateVersion = "22.11"; diff --git a/tests/modules/programs/xmobar/basic-configuration.nix b/tests/modules/programs/xmobar/basic-configuration.nix index bbd9420ea..897094417 100644 --- a/tests/modules/programs/xmobar/basic-configuration.nix +++ b/tests/modules/programs/xmobar/basic-configuration.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, ... }: { config = { programs.xmobar = { enable = true; diff --git a/tests/modules/programs/zellij/enable-shells.nix b/tests/modules/programs/zellij/enable-shells.nix index 63e13facc..4a35df28d 100644 --- a/tests/modules/programs/zellij/enable-shells.nix +++ b/tests/modules/programs/zellij/enable-shells.nix @@ -4,9 +4,13 @@ programs = { zellij = { enable = true; - enableBashIntegration = true; + + attachExistingSession = true; + exitShellOnExit = true; + enableZshIntegration = true; enableFishIntegration = true; + enableBashIntegration = true; }; bash.enable = true; zsh.enable = true; @@ -32,5 +36,13 @@ assertFileContains \ home-files/.config/fish/config.fish \ 'eval (@zellij@/bin/zellij setup --generate-auto-start fish | string collect)' + + assertFileExists home-path/etc/profile.d/hm-session-vars.sh + assertFileContains \ + home-path/etc/profile.d/hm-session-vars.sh \ + 'export ZELLIJ_AUTO_ATTACH="true"' + assertFileContains \ + home-path/etc/profile.d/hm-session-vars.sh \ + 'export ZELLIJ_AUTO_EXIT="true"' ''; } diff --git a/tests/modules/programs/zsh/aliases.nix b/tests/modules/programs/zsh/aliases.nix new file mode 100644 index 000000000..a3fa2b360 --- /dev/null +++ b/tests/modules/programs/zsh/aliases.nix @@ -0,0 +1,52 @@ +{ config, ... }: + +{ + programs.zsh = { + enable = true; + + shellAliases = { + test1 = "alias"; + test2 = "alias2"; + }; + shellGlobalAliases = { global = "test"; }; + }; + + nmt.script = '' + assertFileExists home-files/.zshrc + + assertFileContent home-files/.zshrc ${ + builtins.toFile "expected-.zshrc" '' + typeset -U path cdpath fpath manpath + 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="@zsh@/share/zsh/$ZSH_VERSION/help" + + autoload -U compinit && compinit + # History options should be set in .zshrc and after oh-my-zsh sourcing. + # See https://github.com/nix-community/home-manager/issues/177. + HISTSIZE="10000" + SAVEHIST="10000" + + HISTFILE="$HOME/.zsh_history" + mkdir -p "$(dirname "$HISTFILE")" + + setopt HIST_FCNTL_LOCK + unsetopt APPEND_HISTORY + setopt HIST_IGNORE_DUPS + unsetopt HIST_IGNORE_ALL_DUPS + unsetopt HIST_SAVE_NO_DUPS + unsetopt HIST_FIND_NO_DUPS + setopt HIST_IGNORE_SPACE + unsetopt HIST_EXPIRE_DUPS_FIRST + setopt SHARE_HISTORY + unsetopt EXTENDED_HISTORY + + + alias -- test1=alias + alias -- test2=alias2 + alias -g -- global=test'' + } + ''; +} diff --git a/tests/modules/programs/zsh/default.nix b/tests/modules/programs/zsh/default.nix index 25aa3b470..0e65a4bab 100644 --- a/tests/modules/programs/zsh/default.nix +++ b/tests/modules/programs/zsh/default.nix @@ -1,12 +1,14 @@ { - zsh-session-variables = ./session-variables.nix; - zsh-history-path-new-default = ./history-path-new-default.nix; - zsh-history-path-new-custom = ./history-path-new-custom.nix; - zsh-history-path-old-default = ./history-path-old-default.nix; - zsh-history-path-old-custom = ./history-path-old-custom.nix; + zsh-abbr = ./zsh-abbr.nix; + zsh-aliases = ./aliases.nix; zsh-history-ignore-pattern = ./history-ignore-pattern.nix; + zsh-history-path-new-custom = ./history-path-new-custom.nix; + zsh-history-path-new-default = ./history-path-new-default.nix; + zsh-history-path-old-custom = ./history-path-old-custom.nix; + zsh-history-path-old-default = ./history-path-old-default.nix; zsh-history-substring-search = ./history-substring-search.nix; zsh-prezto = ./prezto.nix; + zsh-session-variables = ./session-variables.nix; zsh-syntax-highlighting = ./syntax-highlighting.nix; - zsh-abbr = ./zsh-abbr.nix; + zshrc-contents-priorities = ./zshrc-content-priorities.nix; } diff --git a/tests/modules/programs/zsh/syntax-highlighting.nix b/tests/modules/programs/zsh/syntax-highlighting.nix index 27970a123..ed7626fcb 100644 --- a/tests/modules/programs/zsh/syntax-highlighting.nix +++ b/tests/modules/programs/zsh/syntax-highlighting.nix @@ -15,6 +15,6 @@ nmt.script = '' assertFileContains home-files/.zshrc "source ${pkgs.hello}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" assertFileContains home-files/.zshrc "ZSH_HIGHLIGHT_HIGHLIGHTERS+=(brackets pattern cursor)" - assertFileContains home-files/.zshrc "ZSH_HIGHLIGHT_STYLES+=(comment 'fg=#6c6c6c')" + assertFileContains home-files/.zshrc "ZSH_HIGHLIGHT_STYLES[comment]='fg=#6c6c6c'" ''; } diff --git a/tests/modules/programs/zsh/zshrc-content-priorities.nix b/tests/modules/programs/zsh/zshrc-content-priorities.nix new file mode 100644 index 000000000..76657cc89 --- /dev/null +++ b/tests/modules/programs/zsh/zshrc-content-priorities.nix @@ -0,0 +1,74 @@ +{ lib, pkgs, ... }: { + programs.zsh = { + enable = true; + + initContent = lib.mkMerge [ + (lib.mkBefore '' + # High priority (mkBefore) + echo "High priority content" + '') + + (lib.mkAfter '' + # Low priority (mkAfter) + echo "Low priority content" + '') + + '' + # Default priority + echo "Default priority content" + '' + ]; + + zprof.enable = true; + }; + + nmt.script = let + expectedFile = pkgs.writeTextFile { + name = ".zshrc"; + text = '' + zmodload zsh/zprof + + # High priority (mkBefore) + echo "High priority content" + + typeset -U path cdpath fpath manpath + 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="@zsh@/share/zsh/$ZSH_VERSION/help" + + autoload -U compinit && compinit + # History options should be set in .zshrc and after oh-my-zsh sourcing. + # See https://github.com/nix-community/home-manager/issues/177. + HISTSIZE="10000" + SAVEHIST="10000" + + HISTFILE="$HOME/.zsh_history" + mkdir -p "$(dirname "$HISTFILE")" + + setopt HIST_FCNTL_LOCK + unsetopt APPEND_HISTORY + setopt HIST_IGNORE_DUPS + unsetopt HIST_IGNORE_ALL_DUPS + unsetopt HIST_SAVE_NO_DUPS + unsetopt HIST_FIND_NO_DUPS + setopt HIST_IGNORE_SPACE + unsetopt HIST_EXPIRE_DUPS_FIRST + setopt SHARE_HISTORY + unsetopt EXTENDED_HISTORY + + + # Default priority + echo "Default priority content" + + zprof + # Low priority (mkAfter) + echo "Low priority content" + ''; + }; + in '' + assertFileExists home-files/.zshrc + assertFileContent home-files/.zshrc ${expectedFile} + ''; +} diff --git a/tests/modules/services/activitywatch/empty-server-settings.nix b/tests/modules/services/activitywatch/empty-server-settings.nix index 290c1fb0a..3b0c50051 100644 --- a/tests/modules/services/activitywatch/empty-server-settings.nix +++ b/tests/modules/services/activitywatch/empty-server-settings.nix @@ -1,5 +1,3 @@ -{ ... }: - { services.activitywatch.enable = true; diff --git a/tests/modules/services/blanket/basic-configuration.nix b/tests/modules/services/blanket/basic-configuration.nix index f51d5ac0a..f4ded9e9c 100644 --- a/tests/modules/services/blanket/basic-configuration.nix +++ b/tests/modules/services/blanket/basic-configuration.nix @@ -16,7 +16,7 @@ RestartSec=5 [Unit] - After=graphical-session-pre.target + After=graphical-session.target Description=Blanket daemon PartOf=graphical-session.target PartOf=pipewire.service diff --git a/tests/modules/services/clipse/clipse-sway-session-target.nix b/tests/modules/services/clipse/clipse-sway-session-target.nix new file mode 100644 index 000000000..d3223cf6f --- /dev/null +++ b/tests/modules/services/clipse/clipse-sway-session-target.nix @@ -0,0 +1,17 @@ +{ ... }: + +{ + services.clipse = { + enable = true; + systemdTarget = "sway-session.target"; + }; + + test.stubs = { + clipse = { }; + wl-clipboard = { }; + }; + + nmt.script = '' + assertFileExists home-files/.config/systemd/user/clipse.service + ''; +} diff --git a/tests/modules/services/clipse/default.nix b/tests/modules/services/clipse/default.nix new file mode 100644 index 000000000..f92f1b679 --- /dev/null +++ b/tests/modules/services/clipse/default.nix @@ -0,0 +1 @@ +{ clipse-sway-session-target = ./clipse-sway-session-target.nix; } diff --git a/tests/modules/services/davmail/custom-settings.nix b/tests/modules/services/davmail/custom-settings.nix new file mode 100644 index 000000000..012324adc --- /dev/null +++ b/tests/modules/services/davmail/custom-settings.nix @@ -0,0 +1,41 @@ +{ config, pkgs, ... }: { + services.davmail = { + enable = true; + settings = { + "davmail.imapPort" = 4444; + "davmail.oauth.redirectUri" = "urn:ietf:wg:oauth:2.0:oob"; + "davmail.persistToken" = true; + }; + }; + + nmt.script = '' + serviceFile=home-files/.config/systemd/user/davmail.service + assertFileExists $serviceFile + configFile=$(grep -o '/nix/store/.*-davmail.properties' $TESTED/$serviceFile) + assertFileExists $configFile + assertFileContent $configFile ${ + pkgs.writeText "custom-settings.properties" '' + # Generated with Nix + + davmail.caldavPort = 1080 + davmail.disableUpdateCheck = true + davmail.imapPort = 4444 + davmail.ldapPort = 1389 + davmail.logFilePath = ${config.xdg.stateHome}/davmail.log + davmail.logFileSize = 1MB + davmail.mode = auto + davmail.oauth.redirectUri = urn:ietf:wg:oauth:2.0:oob + davmail.oauth.tokenFilePath = ${config.xdg.stateHome}/davmail-tokens + davmail.persistToken = true + davmail.popPort = 1110 + davmail.server = true + davmail.smtpPort = 1025 + davmail.url = https://outlook.office365.com/EWS/Exchange.asmx + log4j.logger.davmail = WARN + log4j.logger.httpclient.wire = WARN + log4j.logger.org.apache.commons.httpclient = WARN + log4j.rootLogger = WARN + '' + } + ''; +} diff --git a/tests/modules/services/davmail/default.nix b/tests/modules/services/davmail/default.nix new file mode 100644 index 000000000..764571e10 --- /dev/null +++ b/tests/modules/services/davmail/default.nix @@ -0,0 +1,4 @@ +{ + davmail-custom-settings = ./custom-settings.nix; + davmail-imitateOutlook = ./imitateOutlook.nix; +} diff --git a/tests/modules/services/davmail/imitateOutlook.nix b/tests/modules/services/davmail/imitateOutlook.nix new file mode 100644 index 000000000..1faf1aa56 --- /dev/null +++ b/tests/modules/services/davmail/imitateOutlook.nix @@ -0,0 +1,37 @@ +{ config, pkgs, ... }: { + services.davmail = { + enable = true; + imitateOutlook = true; + }; + + nmt.script = '' + serviceFile=home-files/.config/systemd/user/davmail.service + assertFileExists $serviceFile + configFile=$(grep -o '/nix/store/.*-davmail.properties' $TESTED/$serviceFile) + assertFileExists $configFile + assertFileContent $configFile ${ + pkgs.writeText "imitateOutlook.properties" '' + # Generated with Nix + + davmail.caldavPort = 1080 + davmail.disableUpdateCheck = true + davmail.imapPort = 1143 + davmail.ldapPort = 1389 + davmail.logFilePath = ${config.xdg.stateHome}/davmail.log + davmail.logFileSize = 1MB + davmail.mode = auto + davmail.oauth.clientId = d3590ed6-52b3-4102-aeff-aad2292ab01c + davmail.oauth.redirectUri = urn:ietf:wg:oauth:2.0:oob + davmail.oauth.tokenFilePath = ${config.xdg.stateHome}/davmail-tokens + davmail.popPort = 1110 + davmail.server = true + davmail.smtpPort = 1025 + davmail.url = https://outlook.office365.com/EWS/Exchange.asmx + log4j.logger.davmail = WARN + log4j.logger.httpclient.wire = WARN + log4j.logger.org.apache.commons.httpclient = WARN + log4j.rootLogger = WARN + '' + } + ''; +} diff --git a/tests/modules/services/easyeffects/default.nix b/tests/modules/services/easyeffects/default.nix new file mode 100644 index 000000000..3994344bb --- /dev/null +++ b/tests/modules/services/easyeffects/default.nix @@ -0,0 +1,4 @@ +{ + easyeffects-service = ./service.nix; + easyeffects-example-preset = ./example-preset.nix; +} diff --git a/tests/modules/services/easyeffects/example-preset.json b/tests/modules/services/easyeffects/example-preset.json new file mode 100644 index 000000000..bc21d8486 --- /dev/null +++ b/tests/modules/services/easyeffects/example-preset.json @@ -0,0 +1,18 @@ +{ + "input": { + "blocklist": [], + "plugins_order": [ + "rnnoise#0" + ], + "rnnoise#0": { + "bypass": false, + "enable-vad": false, + "input-gain": 0.0, + "model-path": "", + "output-gain": 0.0, + "release": 20.0, + "vad-thres": 50.0, + "wet": 0.0 + } + } +} diff --git a/tests/modules/services/easyeffects/example-preset.nix b/tests/modules/services/easyeffects/example-preset.nix new file mode 100644 index 000000000..e6906d8f2 --- /dev/null +++ b/tests/modules/services/easyeffects/example-preset.nix @@ -0,0 +1,36 @@ +{ ... }: + +{ + services.easyeffects = { + enable = true; + extraPresets = { + example-preset = { + input = { + blocklist = [ + + ]; + "plugins_order" = [ "rnnoise#0" ]; + "rnnoise#0" = { + bypass = false; + "enable-vad" = false; + "input-gain" = 0.0; + "model-path" = ""; + "output-gain" = 0.0; + release = 20.0; + "vad-thres" = 50.0; + wet = 0.0; + }; + }; + }; + }; + }; + + test.stubs.easyeffects = { }; + + nmt.script = '' + assertFileContent \ + home-files/.config/easyeffects/input/example-preset.json "${ + ./example-preset.json + }" + ''; +} diff --git a/tests/modules/services/easyeffects/service.nix b/tests/modules/services/easyeffects/service.nix new file mode 100644 index 000000000..86c46374e --- /dev/null +++ b/tests/modules/services/easyeffects/service.nix @@ -0,0 +1,14 @@ +{ ... }: + +{ + services.easyeffects = { enable = true; }; + + test.stubs.easyeffects = { }; + + nmt.script = '' + serviceFile=home-files/.config/systemd/user/easyeffects.service + + assertFileExists $serviceFile + assertFileRegex $serviceFile 'ExecStart=.*/bin/easyeffects' + ''; +} diff --git a/tests/modules/services/fluidsynth/service.nix b/tests/modules/services/fluidsynth/service.nix index 97ca0a4b4..2cefeabb1 100644 --- a/tests/modules/services/fluidsynth/service.nix +++ b/tests/modules/services/fluidsynth/service.nix @@ -1,5 +1,3 @@ -{ ... }: - { services.fluidsynth.enable = true; services.fluidsynth.soundService = "pipewire-pulse"; diff --git a/tests/modules/services/fusuma/expected-service.service b/tests/modules/services/fusuma/expected-service.service index 585d8a85e..e84077daf 100644 --- a/tests/modules/services/fusuma/expected-service.service +++ b/tests/modules/services/fusuma/expected-service.service @@ -6,6 +6,6 @@ Environment=PATH=@coreutils@/bin:@xdotool@/bin:@xorg.xprop@/bin ExecStart=@fusuma@/bin/fusuma [Unit] -After=graphical-session-pre.target +After=graphical-session.target Description=Fusuma services PartOf=graphical-session.target diff --git a/tests/modules/services/hyprpolkitagent/basic-configuration.nix b/tests/modules/services/hyprpolkitagent/basic-configuration.nix new file mode 100644 index 000000000..806d495b9 --- /dev/null +++ b/tests/modules/services/hyprpolkitagent/basic-configuration.nix @@ -0,0 +1,23 @@ +{ + services.hyprpolkitagent.enable = true; + + nmt.script = '' + clientServiceFile=home-files/.config/systemd/user/hyprpolkitagent.service + + assertFileExists $clientServiceFile + assertFileContent $clientServiceFile ${ + builtins.toFile "expected.service" '' + [Install] + WantedBy=graphical-session.target + + [Service] + ExecStart=@hyprpolkitagent@/libexec/hyprpolkitagent + + [Unit] + After=graphical-session.target + Description=Hyprland PolicyKit Agent + PartOf=graphical-session.target + '' + } + ''; +} diff --git a/tests/modules/services/hyprpolkitagent/default.nix b/tests/modules/services/hyprpolkitagent/default.nix new file mode 100644 index 000000000..87aca6dc4 --- /dev/null +++ b/tests/modules/services/hyprpolkitagent/default.nix @@ -0,0 +1 @@ +{ hyprpolkitagent-basic-configuration = ./basic-configuration.nix; } diff --git a/tests/modules/services/imapnotify/imapnotify.nix b/tests/modules/services/imapnotify/imapnotify.nix index 82d6f433b..680405fa5 100644 --- a/tests/modules/services/imapnotify/imapnotify.nix +++ b/tests/modules/services/imapnotify/imapnotify.nix @@ -11,6 +11,7 @@ imapnotify = { enable = true; boxes = [ "Inbox" ]; + extraArgs = [ "--wait 1" ]; onNotify = '' ${pkgs.notmuch}/bin/notmuch new ''; diff --git a/tests/modules/services/imapnotify/imapnotify.service b/tests/modules/services/imapnotify/imapnotify.service index cc1ba77b8..8168e501e 100644 --- a/tests/modules/services/imapnotify/imapnotify.service +++ b/tests/modules/services/imapnotify/imapnotify.service @@ -4,7 +4,7 @@ WantedBy=default.target [Service] Environment=PATH= Environment=NOTMUCH_CONFIG=/home/hm-user/.config/notmuch/default/config -ExecStart=@goimapnotify@/bin/goimapnotify -conf '/nix/store/00000000000000000000000000000000-imapnotify-hm-example.com-config.json' +ExecStart=@goimapnotify@/bin/goimapnotify -conf '/nix/store/00000000000000000000000000000000-imapnotify-hm-example.com-config.json' --wait 1 Restart=always RestartSec=30 Type=simple diff --git a/tests/modules/services/jankyborders/config.nix b/tests/modules/services/jankyborders/config.nix new file mode 100644 index 000000000..f802cd675 --- /dev/null +++ b/tests/modules/services/jankyborders/config.nix @@ -0,0 +1,26 @@ +{ pkgs, ... }: { + services.jankyborders = { + enable = true; + settings = { + active_color = "0xffe2e2e3"; + hidpi = "off"; + inactive_color = "0xff414550"; + style = "round"; + width = 6.0; + }; + }; + + nmt.script = '' + configFile=home-files/.config/borders/bordersrc + assertFileExists $configFile + assertFileIsExecutable "$configFile" + # assertFileContent $configFile ${./jankyborders-config-expected} + assertFileContent "$configFile" ${ + pkgs.writeShellScript "bordersrc" + (builtins.readFile ./jankyborders-config-expected) + } + + serviceFile=LaunchAgents/org.nix-community.home.jankyborders.plist + assertFileExists "$serviceFile" + ''; +} diff --git a/tests/modules/services/jankyborders/default.nix b/tests/modules/services/jankyborders/default.nix new file mode 100644 index 000000000..014e4bc42 --- /dev/null +++ b/tests/modules/services/jankyborders/default.nix @@ -0,0 +1 @@ +{ jankyborders-basic-config = ./config.nix; } diff --git a/tests/modules/services/jankyborders/jankyborders-config-expected b/tests/modules/services/jankyborders/jankyborders-config-expected new file mode 100644 index 000000000..ee8e5ec00 --- /dev/null +++ b/tests/modules/services/jankyborders/jankyborders-config-expected @@ -0,0 +1,9 @@ +options=( + active_color=0xffe2e2e3 + hidpi=off + inactive_color=0xff414550 + style=round + width=6.000000 +) + +@JankyBorders@/bin/borders "${options[@]}" diff --git a/tests/modules/services/lxqt-policykit-agent/basic-configuration.nix b/tests/modules/services/lxqt-policykit-agent/basic-configuration.nix new file mode 100644 index 000000000..8406433a7 --- /dev/null +++ b/tests/modules/services/lxqt-policykit-agent/basic-configuration.nix @@ -0,0 +1,23 @@ +{ + services.lxqt-policykit-agent.enable = true; + + nmt.script = '' + clientServiceFile=home-files/.config/systemd/user/lxqt-policykit-agent.service + + assertFileExists $clientServiceFile + assertFileContent $clientServiceFile ${ + builtins.toFile "expected.service" '' + [Install] + WantedBy=graphical-session.target + + [Service] + ExecStart=@lxqt-policykit@/bin/lxqt-policykit-agent + + [Unit] + After=graphical-session-pre.target + Description=LXQT PolicyKit Agent + PartOf=graphical-session.target + '' + } + ''; +} diff --git a/tests/modules/services/lxqt-policykit-agent/default.nix b/tests/modules/services/lxqt-policykit-agent/default.nix new file mode 100644 index 000000000..1d2d2b8fd --- /dev/null +++ b/tests/modules/services/lxqt-policykit-agent/default.nix @@ -0,0 +1 @@ +{ lxqt-policykit-agent-basic-configuration = ./basic-configuration.nix; } diff --git a/tests/modules/services/macos-remap-keys/basic-agent.plist b/tests/modules/services/macos-remap-keys/basic-agent.plist new file mode 100644 index 000000000..b59f97d99 --- /dev/null +++ b/tests/modules/services/macos-remap-keys/basic-agent.plist @@ -0,0 +1,22 @@ + + + + + KeepAlive + + SuccessfulExit + + + Label + org.nix-community.home.remap-keys + ProgramArguments + + /usr/bin/hidutil + property + --set + { "UserKeyMapping": [ { "HIDKeyboardModifierMappingSrc": 0x700000039, "HIDKeyboardModifierMappingDst": 0x70000002A } ] } + + RunAtLoad + + + \ No newline at end of file diff --git a/tests/modules/services/macos-remap-keys/basic-configuration.nix b/tests/modules/services/macos-remap-keys/basic-configuration.nix new file mode 100644 index 000000000..7cc0b9018 --- /dev/null +++ b/tests/modules/services/macos-remap-keys/basic-configuration.nix @@ -0,0 +1,12 @@ +{ + services.macos-remap-keys = { + enable = true; + keyboard = { Capslock = "Backspace"; }; + }; + + nmt.script = '' + launchAgent=LaunchAgents/org.nix-community.home.remap-keys.plist + assertFileExists "$launchAgent" + assertFileContent "$launchAgent" ${./basic-agent.plist} + ''; +} diff --git a/tests/modules/services/macos-remap-keys/default.nix b/tests/modules/services/macos-remap-keys/default.nix new file mode 100644 index 000000000..796110f76 --- /dev/null +++ b/tests/modules/services/macos-remap-keys/default.nix @@ -0,0 +1 @@ +{ macos-remap-keys-basic-configuration = ./basic-configuration.nix; } diff --git a/tests/modules/services/mpd/basic-configuration.conf b/tests/modules/services/mpd/basic-configuration.conf index 59b3568b3..810f2b736 100644 --- a/tests/modules/services/mpd/basic-configuration.conf +++ b/tests/modules/services/mpd/basic-configuration.conf @@ -1,11 +1,7 @@ music_directory "/my/music/dir" playlist_directory "/home/hm-user/.local/share/mpd/playlists" db_file "/home/hm-user/.local/share/mpd/tag_cache" - state_file "/home/hm-user/.local/share/mpd/state" sticker_file "/home/hm-user/.local/share/mpd/sticker.sql" -bind_to_address "127.0.0.1" - - - +bind_to_address "127.0.0.1" diff --git a/tests/modules/services/mpd/basic-configuration.service b/tests/modules/services/mpd/basic-configuration.service index 05ec03846..3ea4d8218 100644 --- a/tests/modules/services/mpd/basic-configuration.service +++ b/tests/modules/services/mpd/basic-configuration.service @@ -4,7 +4,7 @@ WantedBy=default.target [Service] Environment=PATH=/home/hm-user/.nix-profile/bin ExecStart=@mpd@/bin/mpd --no-daemon /nix/store/00000000000000000000000000000000-mpd.conf --verbose -ExecStartPre=@bash@/bin/bash -c "/nix/store/00000000000000000000000000000000-coreutils/bin/mkdir -p '/home/hm-user/.local/share/mpd' '/home/hm-user/.local/share/mpd/playlists'" +ExecStartPre=@bash-interactive@/bin/bash -c "/nix/store/00000000000000000000000000000000-coreutils/bin/mkdir -p '/home/hm-user/.local/share/mpd' '/home/hm-user/.local/share/mpd/playlists'" Type=notify [Unit] diff --git a/tests/modules/services/mpd/start-when-needed.service b/tests/modules/services/mpd/start-when-needed.service index 91ce3890c..fd5d83fbd 100644 --- a/tests/modules/services/mpd/start-when-needed.service +++ b/tests/modules/services/mpd/start-when-needed.service @@ -1,7 +1,7 @@ [Service] Environment=PATH=/home/hm-user/.nix-profile/bin ExecStart=@mpd@/bin/mpd --no-daemon /nix/store/00000000000000000000000000000000-mpd.conf --verbose -ExecStartPre=@bash@/bin/bash -c "/nix/store/00000000000000000000000000000000-coreutils/bin/mkdir -p '/home/hm-user/.local/share/mpd' '/home/hm-user/.local/share/mpd/playlists'" +ExecStartPre=@bash-interactive@/bin/bash -c "/nix/store/00000000000000000000000000000000-coreutils/bin/mkdir -p '/home/hm-user/.local/share/mpd' '/home/hm-user/.local/share/mpd/playlists'" Type=notify [Unit] diff --git a/tests/modules/services/mpd/xdg-music-dir.conf b/tests/modules/services/mpd/xdg-music-dir.conf index 56fe71b49..22157d844 100644 --- a/tests/modules/services/mpd/xdg-music-dir.conf +++ b/tests/modules/services/mpd/xdg-music-dir.conf @@ -1,11 +1,7 @@ music_directory "/home/hm-user/Music" playlist_directory "/home/hm-user/.local/share/mpd/playlists" db_file "/home/hm-user/.local/share/mpd/tag_cache" - state_file "/home/hm-user/.local/share/mpd/state" sticker_file "/home/hm-user/.local/share/mpd/sticker.sql" -bind_to_address "127.0.0.1" - - - +bind_to_address "127.0.0.1" diff --git a/tests/modules/services/mpdscribble/basic-configuration.nix b/tests/modules/services/mpdscribble/basic-configuration.nix new file mode 100644 index 000000000..18c02585f --- /dev/null +++ b/tests/modules/services/mpdscribble/basic-configuration.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + services.mpdscribble = { + enable = true; + endpoints = { + "libre.fm" = { + username = "musicfan1992"; + passwordFile = toString ./password-file; + }; + "https://music.com/" = { + username = "musicHATER1000"; + passwordFile = toString ./password-file; + }; + }; + }; + + home.stateVersion = "22.11"; + + test.stubs.mpd = { }; + + nmt.script = '' + serviceFile=$(normalizeStorePaths home-files/.config/systemd/user/mpdscribble.service) + assertFileContent "$serviceFile" ${./basic-configuration.service} + ''; +} diff --git a/tests/modules/services/mpdscribble/basic-configuration.service b/tests/modules/services/mpdscribble/basic-configuration.service new file mode 100644 index 000000000..efa7da9ad --- /dev/null +++ b/tests/modules/services/mpdscribble/basic-configuration.service @@ -0,0 +1,14 @@ +[Install] +WantedBy=default.target + +[Service] +ExecStart=/nix/store/00000000000000000000000000000000-mpdscribble-start +ExecStartPre=+/nix/store/00000000000000000000000000000000-mpdscribble-pre-start/bin/mpdscribble-pre-start +RuntimeDirectory=mpdscribble +RuntimeDirectoryMode=700 +StateDirectory=mpdscribble + +[Unit] +After=network.target +After=mpd.service +Description=mpdscribble mpd scrobble client diff --git a/tests/modules/services/mpdscribble/default.nix b/tests/modules/services/mpdscribble/default.nix new file mode 100644 index 000000000..b44dae9dd --- /dev/null +++ b/tests/modules/services/mpdscribble/default.nix @@ -0,0 +1 @@ +{ mpdscribble-basic-configuration = ./basic-configuration.nix; } diff --git a/tests/modules/services/ollama/darwin/expected-agent.plist b/tests/modules/services/ollama/darwin/expected-agent.plist index a159fd980..97ed3c8ae 100644 --- a/tests/modules/services/ollama/darwin/expected-agent.plist +++ b/tests/modules/services/ollama/darwin/expected-agent.plist @@ -28,4 +28,4 @@ serve - + \ No newline at end of file diff --git a/tests/modules/services/parcellite/parcellite-expected.service b/tests/modules/services/parcellite/parcellite-expected.service index f1e7e2333..7e0865aa7 100644 --- a/tests/modules/services/parcellite/parcellite-expected.service +++ b/tests/modules/services/parcellite/parcellite-expected.service @@ -6,7 +6,7 @@ ExecStart=@parcellite@/bin/parcellite --no-icon Restart=on-abort [Unit] -After=graphical-session-pre.target +After=graphical-session.target After=tray.target Description=Lightweight GTK+ clipboard manager PartOf=graphical-session.target diff --git a/tests/modules/services/pasystray/expected.service b/tests/modules/services/pasystray/expected.service index 7bea7f215..871f01255 100644 --- a/tests/modules/services/pasystray/expected.service +++ b/tests/modules/services/pasystray/expected.service @@ -6,7 +6,7 @@ Environment=PATH=@paprefs@/bin:@pavucontrol@/bin ExecStart=@pasystray@/bin/pasystray -g [Unit] -After=graphical-session-pre.target +After=graphical-session.target After=tray.target Description=PulseAudio system tray PartOf=graphical-session.target diff --git a/tests/modules/services/picom/picom-basic-configuration-expected.service b/tests/modules/services/picom/picom-basic-configuration-expected.service index 6aeef2249..c0463eeff 100644 --- a/tests/modules/services/picom/picom-basic-configuration-expected.service +++ b/tests/modules/services/picom/picom-basic-configuration-expected.service @@ -7,6 +7,6 @@ Restart=always RestartSec=3 [Unit] -After=graphical-session-pre.target +After=graphical-session.target Description=Picom X11 compositor PartOf=graphical-session.target diff --git a/tests/modules/services/podman-linux/build-expected.service b/tests/modules/services/podman-linux/build-expected.service new file mode 100644 index 000000000..ab4064c22 --- /dev/null +++ b/tests/modules/services/podman-linux/build-expected.service @@ -0,0 +1,30 @@ +# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator +# +# Automatically generated by home-manager for podman build configuration +# DO NOT EDIT THIS FILE DIRECTLY +# +# my-bld.build +[X-Build] +Environment= +File=/nix/store/00000000000000000000000000000000-Containerfile +ImageTag=homemanager/my-bld +Label=nix.home-manager.managed=true +TLSVerify=true + +[Install] +WantedBy=default.target +WantedBy=multi-user.target + +[Service] +RemainAfterExit=yes +TimeoutStartSec=300 +ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman build --tls-verify --tag homemanager/my-bld --label nix.home-manager.managed=true --file /nix/store/00000000000000000000000000000000-Containerfile +SyslogIdentifier=%N +Type=oneshot + +[Unit] +Wants=podman-user-wait-network-online.service +After=podman-user-wait-network-online.service +Description=Service for build my-bld +RequiresMountsFor=%t/containers +SourcePath=/nix/store/00000000000000000000000000000000-home-build-podman-my-bld/quadlets/podman-my-bld.build diff --git a/tests/modules/services/podman-linux/build.nix b/tests/modules/services/podman-linux/build.nix new file mode 100644 index 000000000..27052c6a4 --- /dev/null +++ b/tests/modules/services/podman-linux/build.nix @@ -0,0 +1,44 @@ +{ pkgs, ... }: + +{ + imports = [ ./podman-stubs.nix ]; + + services.podman = { + enable = true; + builds = { + "my-bld" = { + file = let + containerFile = pkgs.writeTextFile { + name = "Containerfile"; + text = '' + FROM docker.io/alpine:latest + ''; + }; + in "${containerFile}"; + }; + + "my-bld-2" = { + file = "https://www.github.com/././Containerfile"; + extraConfig = { + Build.ImageTag = [ "locahost/somethingelse" "localhost/anothertag" ]; + }; + }; + }; + }; + + test.asserts.assertions.expected = [ + '' + In 'my-bld-2' config. Build.ImageTag: '[ "locahost/somethingelse" "localhost/anothertag" ]' does not contain 'homemanager/my-bld-2'.'' + ]; + + nmt.script = '' + configPath=home-files/.config/systemd/user + buildFile=$configPath/podman-my-bld-build.service + + assertFileExists $buildFile + + buildFile=$(normalizeStorePaths $buildFile) + + assertFileContent $buildFile ${./build-expected.service} + ''; +} diff --git a/tests/modules/services/podman-linux/container-expected.service b/tests/modules/services/podman-linux/container-expected.service index d40e24bec..7d5072de9 100644 --- a/tests/modules/services/podman-linux/container-expected.service +++ b/tests/modules/services/podman-linux/container-expected.service @@ -27,7 +27,7 @@ WantedBy=default.target WantedBy=multi-user.target [Service] -Environment=PATH=/run/wrappers/bin:/run/current-system/sw/bin:/home/hm-user/.nix-profile/bin +Environment=PATH=/run/wrappers/bin:/run/current-system/sw/bin:/home/hm-user/.nix-profile/bin:@systemd@/bin Restart=on-failure TimeoutStopSec=30 Environment=PODMAN_SYSTEMD_UNIT=%n @@ -43,7 +43,6 @@ ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman run --na [Unit] Wants=podman-user-wait-network-online.service After=podman-user-wait-network-online.service -After=network.target Before=fake.target Description=home-manager test SourcePath=/nix/store/00000000000000000000000000000000-home-container-podman-my-container/quadlets/podman-my-container.container diff --git a/tests/modules/services/podman-linux/default.nix b/tests/modules/services/podman-linux/default.nix index a5ba9467e..c7f04bdaf 100644 --- a/tests/modules/services/podman-linux/default.nix +++ b/tests/modules/services/podman-linux/default.nix @@ -1,7 +1,10 @@ { podman-configuration = ./configuration.nix; podman-container = ./container.nix; + podman-build = ./build.nix; + podman-image = ./image.nix; podman-integration = ./integration.nix; podman-manifest = ./manifest.nix; podman-network = ./network.nix; + podman-volume = ./volume.nix; } diff --git a/tests/modules/services/podman-linux/image-expected.service b/tests/modules/services/podman-linux/image-expected.service new file mode 100644 index 000000000..2a2e688e3 --- /dev/null +++ b/tests/modules/services/podman-linux/image-expected.service @@ -0,0 +1,28 @@ +# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator +# +# Automatically generated by home-manager for podman image configuration +# DO NOT EDIT THIS FILE DIRECTLY +# +# my-img.image +[X-Image] +Image=docker.io/alpine:latest +TLSVerify=true + +[Install] +WantedBy=default.target +WantedBy=multi-user.target + +[Service] +ExecStartPre=/nix/store/00000000000000000000000000000000-await-podman-unshare +RemainAfterExit=yes +TimeoutStartSec=300 +ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman image pull --tls-verify docker.io/alpine:latest +SyslogIdentifier=%N +Type=oneshot + +[Unit] +Wants=podman-user-wait-network-online.service +After=podman-user-wait-network-online.service +Description=Service for image my-img +SourcePath=/nix/store/00000000000000000000000000000000-home-image-podman-my-img/quadlets/podman-my-img.image +RequiresMountsFor=%t/containers diff --git a/tests/modules/services/podman-linux/image.nix b/tests/modules/services/podman-linux/image.nix new file mode 100644 index 000000000..98560e34d --- /dev/null +++ b/tests/modules/services/podman-linux/image.nix @@ -0,0 +1,18 @@ +{ + imports = [ ./podman-stubs.nix ]; + + services.podman = { + enable = true; + images = { "my-img" = { image = "docker.io/alpine:latest"; }; }; + }; + + nmt.script = '' + configPath=home-files/.config/systemd/user + imageFile=$configPath/podman-my-img-image.service + assertFileExists $imageFile + + imageFile=$(normalizeStorePaths $imageFile) + + assertFileContent $imageFile ${./image-expected.service} + ''; +} diff --git a/tests/modules/services/podman-linux/integration-build-expected.service b/tests/modules/services/podman-linux/integration-build-expected.service new file mode 100644 index 000000000..03808a4cf --- /dev/null +++ b/tests/modules/services/podman-linux/integration-build-expected.service @@ -0,0 +1,30 @@ +# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator +# +# Automatically generated by home-manager for podman build configuration +# DO NOT EDIT THIS FILE DIRECTLY +# +# my-bld.build +[X-Build] +Environment= +File=/nix/store/00000000000000000000000000000000-Containerfile +ImageTag=homemanager/my-bld +Label=nix.home-manager.managed=true +TLSVerify=true + +[Install] +WantedBy=default.target +WantedBy=multi-user.target + +[Service] +RemainAfterExit=yes +TimeoutStartSec=300 +ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman build --tls-verify --tag homemanager/my-bld --label nix.home-manager.managed=true --file /nix/store/00000000000000000000000000000000-Containerfile +SyslogIdentifier=%N +Type=oneshot + +[Unit] +Wants=podman-user-wait-network-online.service +After=podman-user-wait-network-online.service +Description=Service for build my-bld +RequiresMountsFor=%t/containers +SourcePath=/nix/store/00000000000000000000000000000000-home-container-podman-my-container-bld/quadlets/podman-my-bld.build diff --git a/tests/modules/services/podman-linux/integration-container-bld-expected.service b/tests/modules/services/podman-linux/integration-container-bld-expected.service new file mode 100644 index 000000000..582290179 --- /dev/null +++ b/tests/modules/services/podman-linux/integration-container-bld-expected.service @@ -0,0 +1,38 @@ +# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator +# +# Automatically generated by home-manager podman container configuration +# DO NOT EDIT THIS FILE DIRECTLY +# +# my-container-bld.container +[X-Container] +ContainerName=my-container-bld +Environment= +Image=podman-my-bld.build +Label=nix.home-manager.managed=true + +[Install] +WantedBy=default.target +WantedBy=multi-user.target + +[Service] +Environment=PATH=/run/wrappers/bin:/run/current-system/sw/bin:/home/hm-user/.nix-profile/bin:@systemd@/bin +Restart=always +TimeoutStopSec=30 +Environment=PODMAN_SYSTEMD_UNIT=%n +KillMode=mixed +ExecStop=/nix/store/00000000000000000000000000000000-podman/bin/podman rm -v -f -i --cidfile=%t/%N.cid +ExecStopPost=-/nix/store/00000000000000000000000000000000-podman/bin/podman rm -v -f -i --cidfile=%t/%N.cid +Delegate=yes +Type=notify +NotifyAccess=all +SyslogIdentifier=%N +ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman run --name my-container-bld --cidfile=%t/%N.cid --replace --rm --cgroups=split --sdnotify=conmon -d --label nix.home-manager.managed=true homemanager/my-bld + +[Unit] +Wants=podman-user-wait-network-online.service +After=podman-user-wait-network-online.service +Description=Service for container my-container-bld +SourcePath=/nix/store/00000000000000000000000000000000-home-container-podman-my-container-bld/quadlets/podman-my-container-bld.container +Requires=podman-my-bld-build.service +After=podman-my-bld-build.service +RequiresMountsFor=%t/containers diff --git a/tests/modules/services/podman-linux/integration-container-expected.service b/tests/modules/services/podman-linux/integration-container-expected.service index 528d9c18e..4b42e55cc 100644 --- a/tests/modules/services/podman-linux/integration-container-expected.service +++ b/tests/modules/services/podman-linux/integration-container-expected.service @@ -7,17 +7,18 @@ [X-Container] ContainerName=my-container Environment= -Image=docker.io/alpine:latest +Image=podman-my-img.image Label=nix.home-manager.managed=true -Network=my-net +Network=podman-my-app.network Network=externalnet +Volume=podman-my-app.volume:/data [Install] WantedBy=default.target WantedBy=multi-user.target [Service] -Environment=PATH=/run/wrappers/bin:/run/current-system/sw/bin:/home/hm-user/.nix-profile/bin +Environment=PATH=/run/wrappers/bin:/run/current-system/sw/bin:/home/hm-user/.nix-profile/bin:@systemd@/bin Restart=always TimeoutStopSec=30 Environment=PODMAN_SYSTEMD_UNIT=%n @@ -28,14 +29,17 @@ Delegate=yes Type=notify NotifyAccess=all SyslogIdentifier=%N -ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman run --name my-container --cidfile=%t/%N.cid --replace --rm --cgroups=split --network my-net --network externalnet --sdnotify=conmon -d --label nix.home-manager.managed=true docker.io/alpine:latest +ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman run --name my-container --cidfile=%t/%N.cid --replace --rm --cgroups=split --network my-app --network externalnet --sdnotify=conmon -d -v my-app:/data --label nix.home-manager.managed=true docker.io/alpine:latest [Unit] Wants=podman-user-wait-network-online.service After=podman-user-wait-network-online.service -After=network.target -After=podman-my-net-network.service Description=Service for container my-container -Requires=podman-my-net-network.service SourcePath=/nix/store/00000000000000000000000000000000-home-container-podman-my-container/quadlets/podman-my-container.container +Requires=podman-my-img-image.service +After=podman-my-img-image.service RequiresMountsFor=%t/containers +Requires=podman-my-app-network.service +After=podman-my-app-network.service +Requires=podman-my-app-volume.service +After=podman-my-app-volume.service diff --git a/tests/modules/services/podman-linux/integration-image-expected.service b/tests/modules/services/podman-linux/integration-image-expected.service new file mode 100644 index 000000000..2a2e688e3 --- /dev/null +++ b/tests/modules/services/podman-linux/integration-image-expected.service @@ -0,0 +1,28 @@ +# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator +# +# Automatically generated by home-manager for podman image configuration +# DO NOT EDIT THIS FILE DIRECTLY +# +# my-img.image +[X-Image] +Image=docker.io/alpine:latest +TLSVerify=true + +[Install] +WantedBy=default.target +WantedBy=multi-user.target + +[Service] +ExecStartPre=/nix/store/00000000000000000000000000000000-await-podman-unshare +RemainAfterExit=yes +TimeoutStartSec=300 +ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman image pull --tls-verify docker.io/alpine:latest +SyslogIdentifier=%N +Type=oneshot + +[Unit] +Wants=podman-user-wait-network-online.service +After=podman-user-wait-network-online.service +Description=Service for image my-img +SourcePath=/nix/store/00000000000000000000000000000000-home-image-podman-my-img/quadlets/podman-my-img.image +RequiresMountsFor=%t/containers diff --git a/tests/modules/services/podman-linux/integration-network-expected.service b/tests/modules/services/podman-linux/integration-network-expected.service index 5af3bccea..e59ad393e 100644 --- a/tests/modules/services/podman-linux/integration-network-expected.service +++ b/tests/modules/services/podman-linux/integration-network-expected.service @@ -3,7 +3,7 @@ # Automatically generated by home-manager for podman network configuration # DO NOT EDIT THIS FILE DIRECTLY # -# my-net.network +# my-app.network [Install] WantedBy=default.target WantedBy=multi-user.target @@ -11,7 +11,7 @@ WantedBy=multi-user.target [X-Network] Gateway=192.168.123.1 Label=nix.home-manager.managed=true -NetworkName=my-net +NetworkName=my-app Subnet=192.168.123.0/24 [Service] @@ -19,7 +19,7 @@ Environment=PATH=/run/wrappers/bin:/usr/bin:/bin:/usr/sbin:/sbin:@shadow@/bin:/n ExecStartPre=/nix/store/00000000000000000000000000000000-await-podman-unshare RemainAfterExit=yes TimeoutStartSec=15 -ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman network create --ignore --subnet 192.168.123.0/24 --gateway 192.168.123.1 --label nix.home-manager.managed=true my-net +ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman network create --ignore --subnet 192.168.123.0/24 --gateway 192.168.123.1 --label nix.home-manager.managed=true my-app SyslogIdentifier=%N Type=oneshot @@ -27,6 +27,6 @@ Type=oneshot Wants=podman-user-wait-network-online.service After=podman-user-wait-network-online.service After=network.target -Description=Service for network my-net -SourcePath=/nix/store/00000000000000000000000000000000-home-network-podman-my-net/quadlets/podman-my-net.network +Description=Service for network my-app +SourcePath=/nix/store/00000000000000000000000000000000-home-network-podman-my-app/quadlets/podman-my-app.network RequiresMountsFor=%t/containers diff --git a/tests/modules/services/podman-linux/integration-volume-expected.service b/tests/modules/services/podman-linux/integration-volume-expected.service new file mode 100644 index 000000000..9ee9bdb3a --- /dev/null +++ b/tests/modules/services/podman-linux/integration-volume-expected.service @@ -0,0 +1,33 @@ +# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator +# +# Automatically generated by home-manager for podman volume configuration +# DO NOT EDIT THIS FILE DIRECTLY +# +# my-app.volume +[Install] +WantedBy=default.target +WantedBy=multi-user.target + +[Service] +Environment=PATH=/run/wrappers/bin:/usr/bin:/bin:/usr/sbin:/sbin:@shadow@/bin:/nix/store/00000000000000000000000000000000-coreutils/bin +ExecStartPre=/nix/store/00000000000000000000000000000000-await-podman-unshare +RemainAfterExit=yes +TimeoutStartSec=15 +ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman volume create --ignore --opt copy --opt device=tmpfs --opt type=tmpfs --label nix.home-manager.managed=true --label nix.home-manager.preserve=false my-app +SyslogIdentifier=%N +Type=oneshot + +[Unit] +Wants=podman-user-wait-network-online.service +After=podman-user-wait-network-online.service +Description=Service for volume my-app +SourcePath=/nix/store/00000000000000000000000000000000-home-volume-podman-my-app/quadlets/podman-my-app.volume +RequiresMountsFor=%t/containers + +[X-Volume] +Copy=true +Device=tmpfs +Label=nix.home-manager.managed=true +Label=nix.home-manager.preserve=false +Type=tmpfs +VolumeName=my-app diff --git a/tests/modules/services/podman-linux/integration.nix b/tests/modules/services/podman-linux/integration.nix index 6b28fcd7a..1c73093b4 100644 --- a/tests/modules/services/podman-linux/integration.nix +++ b/tests/modules/services/podman-linux/integration.nix @@ -1,29 +1,69 @@ +{ pkgs, ... }: + { imports = [ ./podman-stubs.nix ]; services.podman = { enable = true; - containers."my-container" = { - image = "docker.io/alpine:latest"; - network = [ "my-net" "externalnet" ]; + builds."my-bld" = { + file = let + containerFile = pkgs.writeTextFile { + name = "Containerfile"; + text = '' + FROM docker.io/alpine:latest + ''; + }; + in "${containerFile}"; }; - networks."my-net" = { + containers = { + "my-container" = { + image = "my-img.image"; + network = [ "my-app.network" "externalnet" ]; + volumes = [ "my-app.volume:/data" ]; + }; + "my-container-bld" = { image = "my-bld.build"; }; + }; + images."my-img" = { image = "docker.io/alpine:latest"; }; + networks."my-app" = { gateway = "192.168.123.1"; subnet = "192.168.123.0/24"; }; + volumes."my-app" = { + device = "tmpfs"; + preserve = false; + type = "tmpfs"; + }; }; nmt.script = '' configPath=home-files/.config/systemd/user + buildFile=$configPath/podman-my-bld-build.service containerFile=$configPath/podman-my-container.service - networkFile=$configPath/podman-my-net-network.service + containerBldFile=$configPath/podman-my-container-bld.service + imageFile=$configPath/podman-my-img-image.service + networkFile=$configPath/podman-my-app-network.service + volumeFile=$configPath/podman-my-app-volume.service + assertFileExists $buildFile assertFileExists $containerFile + assertFileExists $containerBldFile + assertFileExists $imageFile assertFileExists $networkFile + assertFileExists $volumeFile + buildFile=$(normalizeStorePaths $buildFile) containerFile=$(normalizeStorePaths $containerFile) + containerBldFile=$(normalizeStorePaths $containerBldFile) + imageFile=$(normalizeStorePaths $imageFile) networkFile=$(normalizeStorePaths $networkFile) + volumeFile=$(normalizeStorePaths $volumeFile) + assertFileContent $buildFile ${./integration-build-expected.service} assertFileContent $containerFile ${./integration-container-expected.service} + assertFileContent $containerBldFile ${ + ./integration-container-bld-expected.service + } + assertFileContent $imageFile ${./integration-image-expected.service} assertFileContent $networkFile ${./integration-network-expected.service} + assertFileContent $volumeFile ${./integration-volume-expected.service} ''; } diff --git a/tests/modules/services/podman-linux/volume-expected.service b/tests/modules/services/podman-linux/volume-expected.service new file mode 100644 index 000000000..73d4c049f --- /dev/null +++ b/tests/modules/services/podman-linux/volume-expected.service @@ -0,0 +1,36 @@ +# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator +# +# Automatically generated by home-manager for podman volume configuration +# DO NOT EDIT THIS FILE DIRECTLY +# +# my-vol.volume +[Install] +WantedBy=default.target +WantedBy=multi-user.target + +[Service] +Environment=PATH=/run/wrappers/bin:/usr/bin:/bin:/usr/sbin:/sbin:@shadow@/bin:/nix/store/00000000000000000000000000000000-coreutils/bin +ExecStartPre=/nix/store/00000000000000000000000000000000-await-podman-unshare +RemainAfterExit=yes +TimeoutStartSec=15 +ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman volume create --ignore --opt copy --opt device=tmpfs --opt type=tmpfs --opt o=uid=1000,gid=1000 --label nix.home-manager.managed=true --label nix.home-manager.preserve=true --module=/etc/nvd.conf my-vol +SyslogIdentifier=%N +Type=oneshot + +[Unit] +Wants=podman-user-wait-network-online.service +After=podman-user-wait-network-online.service +Description=Service for volume my-vol +SourcePath=/nix/store/00000000000000000000000000000000-home-volume-podman-my-vol/quadlets/podman-my-vol.volume +RequiresMountsFor=%t/containers + +[X-Volume] +Copy=true +Device=tmpfs +Group=1000 +Label=nix.home-manager.managed=true +Label=nix.home-manager.preserve=true +PodmanArgs=--module=/etc/nvd.conf +Type=tmpfs +User=1000 +VolumeName=my-vol diff --git a/tests/modules/services/podman-linux/volume.nix b/tests/modules/services/podman-linux/volume.nix new file mode 100644 index 000000000..885662b2f --- /dev/null +++ b/tests/modules/services/podman-linux/volume.nix @@ -0,0 +1,35 @@ +{ + imports = [ ./podman-stubs.nix ]; + + services.podman = { + enable = true; + volumes = { + "my-vol" = { + device = "tmpfs"; + extraConfig = { Volume = { User = 1000; }; }; + extraPodmanArgs = [ "--module=/etc/nvd.conf" ]; + group = 1000; + type = "tmpfs"; + }; + + "my-vol-2" = { + extraConfig = { Volume = { VolumeName = "some-other-volume-name"; }; }; + }; + }; + }; + + test.asserts.assertions.expected = [ + '' + In 'my-vol-2' config. Volume.VolumeName: 'some-other-volume-name' does not match expected type: value "my-vol-2" (singular enum)'' + ]; + + nmt.script = '' + configPath=home-files/.config/systemd/user + volumeFile=$configPath/podman-my-vol-volume.service + assertFileExists $volumeFile + + volumeFile=$(normalizeStorePaths $volumeFile) + + assertFileContent $volumeFile ${./volume-expected.service} + ''; +} diff --git a/tests/modules/services/polkit-gnome/basic-configuration.nix b/tests/modules/services/polkit-gnome/basic-configuration.nix new file mode 100644 index 000000000..b297e81be --- /dev/null +++ b/tests/modules/services/polkit-gnome/basic-configuration.nix @@ -0,0 +1,23 @@ +{ + services.polkit-gnome.enable = true; + + nmt.script = '' + clientServiceFile=home-files/.config/systemd/user/polkit-gnome.service + + assertFileExists $clientServiceFile + assertFileContent $clientServiceFile ${ + builtins.toFile "expected.service" '' + [Install] + WantedBy=graphical-session.target + + [Service] + ExecStart=@polkit-gnome@/libexec/polkit-gnome-authentication-agent-1 + + [Unit] + After=graphical-session-pre.target + Description=GNOME PolicyKit Agent + PartOf=graphical-session.target + '' + } + ''; +} diff --git a/tests/modules/services/polkit-gnome/default.nix b/tests/modules/services/polkit-gnome/default.nix new file mode 100644 index 000000000..7028eb98b --- /dev/null +++ b/tests/modules/services/polkit-gnome/default.nix @@ -0,0 +1 @@ +{ polkit-gnome-basic-configuration = ./basic-configuration.nix; } diff --git a/tests/modules/services/redshift-gammastep/gammastep-basic-configuration-expected.service b/tests/modules/services/redshift-gammastep/gammastep-basic-configuration-expected.service index 35eaf519f..a877b60f8 100644 --- a/tests/modules/services/redshift-gammastep/gammastep-basic-configuration-expected.service +++ b/tests/modules/services/redshift-gammastep/gammastep-basic-configuration-expected.service @@ -7,7 +7,7 @@ Restart=on-failure RestartSec=3 [Unit] -After=graphical-session-pre.target +After=graphical-session.target Description=Gammastep colour temperature adjuster Documentation=https://gitlab.com/chinstrap/gammastep/ PartOf=graphical-session.target diff --git a/tests/modules/services/redshift-gammastep/redshift-basic-configuration-expected.service b/tests/modules/services/redshift-gammastep/redshift-basic-configuration-expected.service index 5dce5dc19..7177fab8f 100644 --- a/tests/modules/services/redshift-gammastep/redshift-basic-configuration-expected.service +++ b/tests/modules/services/redshift-gammastep/redshift-basic-configuration-expected.service @@ -7,7 +7,7 @@ Restart=on-failure RestartSec=3 [Unit] -After=graphical-session-pre.target +After=graphical-session.target Description=Redshift colour temperature adjuster Documentation=http://jonls.dk/redshift/ PartOf=graphical-session.target diff --git a/tests/modules/services/screen-locker/basic-configuration.nix b/tests/modules/services/screen-locker/basic-configuration.nix index 855370d2b..1cf4fabe2 100644 --- a/tests/modules/services/screen-locker/basic-configuration.nix +++ b/tests/modules/services/screen-locker/basic-configuration.nix @@ -5,6 +5,7 @@ enable = true; inactiveInterval = 5; lockCmd = "${pkgs.i3lock}/bin/i3lock -n -c AA0000"; + lockCmdEnv = [ "DISPLAY=:0" "XAUTHORITY=/custom/path/.Xauthority" ]; xss-lock = { extraOptions = [ "-test" ]; }; xautolock = { enable = true; @@ -19,7 +20,11 @@ assertFileExists $xssService assertFileRegex $xssService 'ExecStart=.*/bin/xss-lock.*-test.*i3lock -n -c AA0000' + assertFileRegex $xssService 'Environment=DISPLAY=:0' + assertFileRegex $xssService 'Environment=XAUTHORITY=/custom/path/.Xauthority' + assertFileRegex $xssService 'Restart=always' assertFileExists $xautolockService assertFileRegex $xautolockService 'ExecStart=.*/bin/xautolock.*-time 5.*-detectsleep.*-test.*' + assertFileRegex $xautolockService 'Restart=always' ''; } diff --git a/tests/modules/services/screen-locker/moved-options.nix b/tests/modules/services/screen-locker/moved-options.nix index 9e0ca0da4..bb49b0489 100644 --- a/tests/modules/services/screen-locker/moved-options.nix +++ b/tests/modules/services/screen-locker/moved-options.nix @@ -5,6 +5,7 @@ enable = true; inactiveInterval = 5; lockCmd = "${pkgs.i3lock}/bin/i3lock -n -c AA0000"; + lockCmdEnv = [ "DISPLAY=:0" "XAUTHORITY=/custom/path/.Xauthority" ]; xssLockExtraOptions = [ "-test" ]; xautolockExtraOptions = [ "-test" ]; enableDetectSleep = true; @@ -15,16 +16,15 @@ nmt.script = (import ./basic-configuration.nix { inherit config pkgs; }).nmt.script; - test.asserts.warnings.expected = with lib; - let - renamed = { - xssLockExtraOptions = "xss-lock.extraOptions"; - xautolockExtraOptions = "xautolock.extraOptions"; - enableDetectSleep = "xautolock.detectSleep"; - }; - in mapAttrsToList (old: new: - builtins.replaceStrings [ "\n" ] [ " " ] '' - The option `services.screen-locker.${old}' defined in - ${showFiles options.services.screen-locker.${old}.files} - has been renamed to `services.screen-locker.${new}'.'') renamed; + test.asserts.warnings.expected = let + renamed = { + xssLockExtraOptions = "xss-lock.extraOptions"; + xautolockExtraOptions = "xautolock.extraOptions"; + enableDetectSleep = "xautolock.detectSleep"; + }; + in lib.mapAttrsToList (old: new: + builtins.replaceStrings [ "\n" ] [ " " ] '' + The option `services.screen-locker.${old}' defined in + ${lib.showFiles options.services.screen-locker.${old}.files} + has been renamed to `services.screen-locker.${new}'.'') renamed; } diff --git a/tests/modules/services/skhd/config.nix b/tests/modules/services/skhd/config.nix new file mode 100644 index 000000000..13d6a2626 --- /dev/null +++ b/tests/modules/services/skhd/config.nix @@ -0,0 +1,25 @@ +{ + services.skhd = { + enable = true; + config = '' + # open terminal, blazingly fast compared to iTerm/Hyper + cmd - return : /Applications/kitty.app/Contents/MacOS/kitty --single-instance -d ~ + + # open qutebrowser + cmd + shift - return : ~/Scripts/qtb.sh + + # open mpv + cmd - m : open -na /Applications/mpv.app $(pbpaste) + ''; + }; + + nmt.script = '' + configFile=home-files/.config/skhd/skhdrc + assertFileExists $configFile + assertFileIsExecutable "$configFile" + assertFileContent $configFile ${./skhd-config-expected} + + serviceFile=LaunchAgents/org.nix-community.home.skhd.plist + assertFileExists "$serviceFile" + ''; +} diff --git a/tests/modules/services/skhd/default.nix b/tests/modules/services/skhd/default.nix new file mode 100644 index 000000000..ad5b46096 --- /dev/null +++ b/tests/modules/services/skhd/default.nix @@ -0,0 +1 @@ +{ skhd-basic-config = ./config.nix; } diff --git a/tests/modules/services/skhd/skhd-config-expected b/tests/modules/services/skhd/skhd-config-expected new file mode 100644 index 000000000..cbfd40a99 --- /dev/null +++ b/tests/modules/services/skhd/skhd-config-expected @@ -0,0 +1,8 @@ +# open terminal, blazingly fast compared to iTerm/Hyper +cmd - return : /Applications/kitty.app/Contents/MacOS/kitty --single-instance -d ~ + +# open qutebrowser +cmd + shift - return : ~/Scripts/qtb.sh + +# open mpv +cmd - m : open -na /Applications/mpv.app $(pbpaste) diff --git a/tests/modules/services/swayidle/basic-configuration.nix b/tests/modules/services/swayidle/basic-configuration.nix index 697c1de46..51a254ff9 100644 --- a/tests/modules/services/swayidle/basic-configuration.nix +++ b/tests/modules/services/swayidle/basic-configuration.nix @@ -44,7 +44,7 @@ WantedBy=graphical-session.target [Service] - Environment=PATH=@bash@/bin + Environment=PATH=@bash-interactive@/bin ExecStart=@swayidle@/bin/dummy -w timeout 50 'notify-send -t 10000 -- "Screen lock in 10 seconds"' timeout 60 'swaylock -fF' timeout 300 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' before-sleep 'swaylock -fF' lock 'swaylock -fF' Restart=always Type=simple diff --git a/tests/modules/services/swww/default.nix b/tests/modules/services/swww/default.nix new file mode 100644 index 000000000..ce316acbc --- /dev/null +++ b/tests/modules/services/swww/default.nix @@ -0,0 +1 @@ +{ swww-graphical-session-target = ./swww-graphical-session-target.nix; } diff --git a/tests/modules/services/swww/swww-graphical-session-target.nix b/tests/modules/services/swww/swww-graphical-session-target.nix new file mode 100644 index 000000000..b21e0b7b4 --- /dev/null +++ b/tests/modules/services/swww/swww-graphical-session-target.nix @@ -0,0 +1,11 @@ +{ config, ... }: { + services.swww = { + enable = true; + package = config.lib.test.mkStubPackage { outPath = "@swww@"; }; + }; + + nmt.script = '' + serviceFile=home-files/.config/systemd/user/swww.service + assertFileContent $serviceFile ${./swww-graphical-session-target.service} + ''; +} diff --git a/tests/modules/services/swww/swww-graphical-session-target.service b/tests/modules/services/swww/swww-graphical-session-target.service new file mode 100644 index 000000000..4c219ff7e --- /dev/null +++ b/tests/modules/services/swww/swww-graphical-session-target.service @@ -0,0 +1,13 @@ +[Install] +WantedBy=graphical-session.target + +[Service] +ExecStart=@swww@/bin/swww-daemon +Restart=always +RestartSec=10 + +[Unit] +After=graphical-session.target +ConditionEnvironment=WAYLAND_DISPLAY +Description=swww-daemon +PartOf=graphical-session.target diff --git a/tests/modules/services/syncthing/common/expected-agent.plist b/tests/modules/services/syncthing/common/expected-agent.plist index 3b9a28ff2..72ec9d0dd 100644 --- a/tests/modules/services/syncthing/common/expected-agent.plist +++ b/tests/modules/services/syncthing/common/expected-agent.plist @@ -15,12 +15,7 @@ Background ProgramArguments - @syncthing@/bin/syncthing - -no-browser - -no-restart - -logflags=0 - -foo - -bar "baz" + @syncthing-wrapper@ \ No newline at end of file diff --git a/tests/modules/services/syncthing/common/extra-options.nix b/tests/modules/services/syncthing/common/extra-options.nix index 9db9f5940..226a5906b 100644 --- a/tests/modules/services/syncthing/common/extra-options.nix +++ b/tests/modules/services/syncthing/common/extra-options.nix @@ -2,6 +2,10 @@ lib.mkMerge [ { + test.stubs.writers = { + extraAttrs.writeBash = (name: fn: "@syncthing-wrapper@"); + }; + services.syncthing = { enable = true; extraOptions = [ "-foo" ''-bar "baz"'' ]; diff --git a/tests/modules/services/window-managers/i3/i3-bar-focused-colors.nix b/tests/modules/services/window-managers/i3/i3-bar-focused-colors.nix index abb4112a7..7524fbee8 100644 --- a/tests/modules/services/window-managers/i3/i3-bar-focused-colors.nix +++ b/tests/modules/services/window-managers/i3/i3-bar-focused-colors.nix @@ -1,5 +1,3 @@ -{ ... }: - { imports = [ ./i3-stubs.nix ]; diff --git a/tests/modules/services/window-managers/i3/i3-followmouse.nix b/tests/modules/services/window-managers/i3/i3-followmouse.nix index db84abd1f..9477d89d1 100644 --- a/tests/modules/services/window-managers/i3/i3-followmouse.nix +++ b/tests/modules/services/window-managers/i3/i3-followmouse.nix @@ -1,5 +1,3 @@ -{ ... }: - { xsession.windowManager.i3 = { enable = true; diff --git a/tests/modules/services/window-managers/i3/i3-fonts-deprecated.nix b/tests/modules/services/window-managers/i3/i3-fonts-deprecated.nix index fefff9904..1aa0c9bcc 100644 --- a/tests/modules/services/window-managers/i3/i3-fonts-deprecated.nix +++ b/tests/modules/services/window-managers/i3/i3-fonts-deprecated.nix @@ -1,5 +1,3 @@ -{ ... }: - { imports = [ ./i3-stubs.nix ]; diff --git a/tests/modules/services/window-managers/i3/i3-fonts.nix b/tests/modules/services/window-managers/i3/i3-fonts.nix index 061f7a0bd..1f3ae01c1 100644 --- a/tests/modules/services/window-managers/i3/i3-fonts.nix +++ b/tests/modules/services/window-managers/i3/i3-fonts.nix @@ -1,5 +1,3 @@ -{ ... }: - { imports = [ ./i3-stubs.nix ]; diff --git a/tests/modules/services/window-managers/i3/i3-null-config.nix b/tests/modules/services/window-managers/i3/i3-null-config.nix index 8433b0c7f..d0be9a60b 100644 --- a/tests/modules/services/window-managers/i3/i3-null-config.nix +++ b/tests/modules/services/window-managers/i3/i3-null-config.nix @@ -1,5 +1,3 @@ -{ ... }: - { imports = [ ./i3-stubs.nix ]; diff --git a/tests/modules/services/window-managers/i3/i3-workspace-default.nix b/tests/modules/services/window-managers/i3/i3-workspace-default.nix index 733d619fd..f9fd598df 100644 --- a/tests/modules/services/window-managers/i3/i3-workspace-default.nix +++ b/tests/modules/services/window-managers/i3/i3-workspace-default.nix @@ -1,5 +1,3 @@ -{ ... }: - { imports = [ ./i3-stubs.nix ]; diff --git a/tests/modules/services/window-managers/i3/i3-workspace-output.nix b/tests/modules/services/window-managers/i3/i3-workspace-output.nix index 4e31acdef..028e891b1 100644 --- a/tests/modules/services/window-managers/i3/i3-workspace-output.nix +++ b/tests/modules/services/window-managers/i3/i3-workspace-output.nix @@ -1,5 +1,3 @@ -{ ... }: - let i3 = { ws1 = "1"; diff --git a/tests/modules/services/wlsunset/wlsunset-service-expected.service b/tests/modules/services/wlsunset/wlsunset-service-expected.service index fecd05b9f..d4006618f 100644 --- a/tests/modules/services/wlsunset/wlsunset-service-expected.service +++ b/tests/modules/services/wlsunset/wlsunset-service-expected.service @@ -5,5 +5,6 @@ WantedBy=test.target ExecStart=@wlsunset@/bin/wlsunset -L 128.8 -T 6000 -g 0.6 -l 12.3 -t 3500 [Unit] +After=graphical-session.target Description=Day/night gamma adjustments for Wayland compositors. PartOf=graphical-session.target diff --git a/tests/modules/programs/wpaperd/default.nix b/tests/modules/services/wpaperd/default.nix similarity index 100% rename from tests/modules/programs/wpaperd/default.nix rename to tests/modules/services/wpaperd/default.nix diff --git a/tests/modules/programs/wpaperd/wpaperd-example-settings.nix b/tests/modules/services/wpaperd/wpaperd-example-settings.nix similarity index 94% rename from tests/modules/programs/wpaperd/wpaperd-example-settings.nix rename to tests/modules/services/wpaperd/wpaperd-example-settings.nix index a10a2eac3..30cb0ffc3 100644 --- a/tests/modules/programs/wpaperd/wpaperd-example-settings.nix +++ b/tests/modules/services/wpaperd/wpaperd-example-settings.nix @@ -1,5 +1,5 @@ { - programs.wpaperd = { + services.wpaperd = { enable = true; settings = { eDP-1 = { @@ -9,6 +9,7 @@ DP-2 = { path = "/home/foo/Pictures/Anime"; sorting = "descending"; + }; }; }; diff --git a/tests/modules/programs/wpaperd/wpaperd-expected-settings.toml b/tests/modules/services/wpaperd/wpaperd-expected-settings.toml similarity index 100% rename from tests/modules/programs/wpaperd/wpaperd-expected-settings.toml rename to tests/modules/services/wpaperd/wpaperd-expected-settings.toml diff --git a/tests/modules/services/yubikey-agent-darwin/service.nix b/tests/modules/services/yubikey-agent-darwin/service.nix index aa09695d0..99b68dc6f 100644 --- a/tests/modules/services/yubikey-agent-darwin/service.nix +++ b/tests/modules/services/yubikey-agent-darwin/service.nix @@ -28,7 +28,7 @@ Background ProgramArguments - @yubikey-agent@/bin/yubikey-agent + @yubikey-agent@/bin/yubikey-agent -l /tmp/yubikey-agent.sock @@ -43,8 +43,7 @@ - - '' + '' } ''; } diff --git a/tests/modules/systemd/timers.nix b/tests/modules/systemd/timers.nix index b9d167e3b..2d48e9fde 100644 --- a/tests/modules/systemd/timers.nix +++ b/tests/modules/systemd/timers.nix @@ -1,5 +1,3 @@ -{ ... }: - { systemd.user.timers.test-timer = { Unit = { Description = "A basic test timer"; }; diff --git a/tests/modules/targets-darwin/darwin.nix b/tests/modules/targets-darwin/darwin.nix index 511ae87fd..640b17783 100644 --- a/tests/modules/targets-darwin/darwin.nix +++ b/tests/modules/targets-darwin/darwin.nix @@ -1,14 +1,9 @@ -{ config, lib, pkgs, ... }: - -with lib; - +{ pkgs, ... }: let - darwinTestApp = pkgs.runCommandLocal "target-darwin-example-app" { } '' mkdir -p $out/Applications touch $out/Applications/example-app ''; - in { config = { home.packages = [ darwinTestApp ]; diff --git a/tests/modules/targets-darwin/user-defaults.nix b/tests/modules/targets-darwin/user-defaults.nix index bb23f718d..a99baf6d0 100644 --- a/tests/modules/targets-darwin/user-defaults.nix +++ b/tests/modules/targets-darwin/user-defaults.nix @@ -1,5 +1,3 @@ -{ lib, ... }: - { config = { targets.darwin = { @@ -10,9 +8,9 @@ nmt.script = '' assertFileRegex activate \ - "/usr/bin/defaults import 'com.apple.desktopservices' /nix/store/[a-z0-9]\\{32\\}-com\\.apple\\.desktopservices\\.plist" + "/usr/bin/defaults import com.apple.desktopservices /nix/store/[a-z0-9]\\{32\\}-com\\.apple\\.desktopservices\\.plist" assertFileRegex activate \ - "/usr/bin/defaults -currentHost import 'com.apple.controlcenter' /nix/store/[a-z0-9]\\{32\\}-com\\.apple\\.controlcenter\\.plist" + "/usr/bin/defaults -currentHost import com.apple.controlcenter /nix/store/[a-z0-9]\\{32\\}-com\\.apple\\.controlcenter\\.plist" ''; }; } diff --git a/tests/modules/targets-linux/generic-linux.nix b/tests/modules/targets-linux/generic-linux.nix index 88cec8a00..aba0e39d0 100644 --- a/tests/modules/targets-linux/generic-linux.nix +++ b/tests/modules/targets-linux/generic-linux.nix @@ -1,9 +1,6 @@ -{ config, lib, pkgs, ... }: - -with lib; - +{ lib, pkgs, ... }: let - expectedXdgDataDirs = concatStringsSep ":" [ + expectedXdgDataDirs = lib.concatStringsSep ":" [ "\${NIX_STATE_DIR:-/nix/var/nix}/profiles/default/share" "/home/hm-user/.nix-profile/share" "/usr/share/ubuntu" @@ -12,7 +9,6 @@ let "/var/lib/snapd/desktop" "/foo" ]; - in { config = { targets.genericLinux.enable = true; diff --git a/tests/modules/xresources/empty.nix b/tests/modules/xresources/empty.nix index e02e0fbfe..3c4102781 100644 --- a/tests/modules/xresources/empty.nix +++ b/tests/modules/xresources/empty.nix @@ -1,5 +1,3 @@ -{ ... }: - { xresources.properties = { }; diff --git a/tests/modules/xresources/xresources.nix b/tests/modules/xresources/xresources.nix index 3f8a83678..5fead37da 100644 --- a/tests/modules/xresources/xresources.nix +++ b/tests/modules/xresources/xresources.nix @@ -1,5 +1,3 @@ -{ ... }: - { xresources = { properties = { diff --git a/tests/stubs.nix b/tests/stubs.nix index 25863143d..66d7265e6 100644 --- a/tests/stubs.nix +++ b/tests/stubs.nix @@ -1,8 +1,6 @@ { config, lib, pkgs, ... }: - -with lib; - let + inherit (lib) mkOption types; stubType = types.submodule ({ name, ... }: { options = { @@ -15,13 +13,13 @@ let outPath = mkOption { type = types.nullOr types.str; default = "@${name}@"; - defaultText = literalExpression ''"@''${name}@"''; + defaultText = lib.literalExpression ''"@''${name}@"''; }; version = mkOption { type = types.nullOr types.str; default = null; - defaultText = literalExpression "pkgs.\${name}.version or null"; + defaultText = lib.literalExpression "pkgs.\${name}.version or null"; }; buildScript = mkOption { @@ -52,7 +50,7 @@ let meta.mainProgram = name; } buildScript; - stubbedPkg = pkg // optionalAttrs (outPath != null) { + stubbedPkg = pkg // lib.optionalAttrs (outPath != null) { inherit outPath; # Prevent getOutput from descending into outputs @@ -63,7 +61,8 @@ let buildHost = pkg; hostTarget = pkg; }; - } // optionalAttrs (version != null) { inherit version; } // extraAttrs; + } // lib.optionalAttrs (version != null) { inherit version; } + // extraAttrs; in stubbedPkg; in { @@ -90,11 +89,12 @@ in { config = { lib.test.mkStubPackage = mkStubPackage; - test.stubOverlays = [ ] ++ optional (config.test.stubs != { }) (self: super: - mapAttrs (n: v: - builtins.traceVerbose "${n} - stubbed" (mkStubPackage (v - // optionalAttrs (v.version == null) { - version = super.${n}.version or null; - }))) config.test.stubs) ++ config.test.unstubs; + test.stubOverlays = [ ] ++ lib.optional (config.test.stubs != { }) + (self: super: + lib.mapAttrs (n: v: + builtins.traceVerbose "${n} - stubbed" (mkStubPackage (v + // lib.optionalAttrs (v.version == null) { + version = super.${n}.version or null; + }))) config.test.stubs) ++ config.test.unstubs; }; }