diff --git a/flake-module.nix b/flake-module.nix index 59091dcde..269add846 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. @@ -15,7 +15,7 @@ in { ''; }; homeManagerModules = mkOption { - type = types.lazyAttrsOf types.unspecified; + type = types.lazyAttrsOf types.deferredModule; default = { }; apply = mapAttrs (k: v: { _class = "homeManager"; diff --git a/flake.lock b/flake.lock index 6ca2bd080..1fd6ae2ee 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1739020877, - "narHash": "sha256-mIvECo/NNdJJ/bXjNqIh8yeoSjVLAuDuTUzAo7dzs8Y=", + "lastModified": 1739736696, + "narHash": "sha256-zON2GNBkzsIyALlOCFiEBcIjI4w38GYOb+P+R4S8Jsw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a79cfe0ebd24952b580b1cf08cd906354996d547", + "rev": "d74a2335ac9c133d6bbec9fc98d91a77f1604c1f", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 4b797355e..918507dde 100644 --- a/flake.nix +++ b/flake.nix @@ -6,29 +6,22 @@ outputs = { self, nixpkgs, ... }: { nixosModules = rec { - home-manager = import ./nixos; + home-manager = ./nixos; default = home-manager; }; - # deprecated in Nix 2.8 - nixosModule = self.nixosModules.default; darwinModules = rec { - home-manager = import ./nix-darwin; + home-manager = ./nix-darwin; default = home-manager; }; - # unofficial; deprecated in Nix 2.8 - darwinModule = self.darwinModules.default; flakeModules = rec { - home-manager = import ./flake-module.nix; + home-manager = ./flake-module.nix; default = home-manager; }; templates = { - standalone = { - path = ./templates/standalone; - description = "Standalone setup"; - }; + default = self.templates.standalone; nixos = { path = ./templates/nixos; description = "Home Manager as a NixOS module,"; @@ -37,10 +30,12 @@ path = ./templates/nix-darwin; description = "Home Manager as a nix-darwin module,"; }; + standalone = { + path = ./templates/standalone; + description = "Standalone setup"; + }; }; - defaultTemplate = self.templates.standalone; - lib = import ./lib { inherit (nixpkgs) lib; }; } // (let forAllSystems = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed; @@ -69,7 +64,5 @@ docs-json = docs.options.json; docs-manpages = docs.manPages; }); - - defaultPackage = forAllSystems (system: self.packages.${system}.default); }); } diff --git a/modules/accounts/email.nix b/modules/accounts/email.nix index e8cc708ed..437c8d558 100644 --- a/modules/accounts/email.nix +++ b/modules/accounts/email.nix @@ -268,10 +268,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 { diff --git a/modules/config/home-cursor.nix b/modules/config/home-cursor.nix index 42c259455..8c28d0fd1 100644 --- a/modules/config/home-cursor.nix +++ b/modules/config/home-cursor.nix @@ -56,6 +56,11 @@ let description = "The cursor size for hyprcursor."; }; }; + + sway = { + enable = mkEnableOption + "sway config generation for {option}`home.pointerCursor`"; + }; }; }; @@ -197,5 +202,18 @@ in { 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}"; + }; + }; + }; + }; + }) ]); } diff --git a/modules/i18n/input-method/fcitx5.nix b/modules/i18n/input-method/fcitx5.nix index 3e4e2f26d..4ec3b8fdd 100644 --- a/modules/i18n/input-method/fcitx5.nix +++ b/modules/i18n/input-method/fcitx5.nix @@ -54,6 +54,7 @@ in { 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/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 3663f8c33..847c70b3c 100644 --- a/modules/lib/maintainers.nix +++ b/modules/lib/maintainers.nix @@ -5,7 +5,6 @@ # are expected to be follow the same format as described in [1]. # # [1] https://github.com/NixOS/nixpkgs/blob/fca0d6e093c82b31103dc0dacc48da2a9b06e24b/maintainers/maintainer-list.nix#LC1 - { aabccd021 = { name = "Muhamad Abdurahman"; @@ -113,6 +112,12 @@ github = "diniamo"; githubId = 55629891; }; + dsoverlord = { + name = "Kirill Zakharov"; + email = "dsoverlord@vk.com"; + github = "dsoverlord"; + githubId = 78819443; + }; dwagenk = { email = "dwagenk@mailbox.org"; github = "dwagenk"; @@ -664,4 +669,26 @@ github = "ckgxrg-salt"; githubId = 165614491; }; + HPsaucii = { + name = "Holly Powell"; + email = "me@hpsaucii.dev"; + github = "HPsaucii"; + githubId = 126502193; + keys = [{ + longkeyid = "rsa4096/0xEDB2C634166AE6AD"; + 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"; + }; } 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..37d3c65d8 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -2062,6 +2062,58 @@ 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. + ''; + } ]; }; } diff --git a/modules/misc/xdg.nix b/modules/misc/xdg.nix index b916e88fb..e68e16a8b 100644 --- a/modules/misc/xdg.nix +++ b/modules/misc/xdg.nix @@ -143,6 +143,7 @@ in { (mapAttrs' (name: file: nameValuePair "${cfg.stateHome}/${name}" file) cfg.stateFile) { "${cfg.cacheHome}/.keep".text = ""; } + { "${cfg.stateHome}/.keep".text = ""; } ]; } ]; diff --git a/modules/modules.nix b/modules/modules.nix index 7855df99f..a9c8db461 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -30,6 +30,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 +90,7 @@ let ./programs/dircolors.nix ./programs/direnv.nix ./programs/discocss.nix + ./programs/earthly.nix ./programs/eclipse.nix ./programs/emacs.nix ./programs/eww.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 @@ -237,6 +240,7 @@ let ./programs/sqls.nix ./programs/ssh.nix ./programs/starship.nix + ./programs/swayimg.nix ./programs/swaylock.nix ./programs/swayr.nix ./programs/taskwarrior.nix @@ -260,6 +264,7 @@ let ./programs/vifm.nix ./programs/vim-vint.nix ./programs/vim.nix + ./programs/vinegar.nix ./programs/vscode.nix ./programs/vscode/haskell.nix ./programs/pywal.nix @@ -269,7 +274,6 @@ let ./programs/wezterm.nix ./programs/wlogout.nix ./programs/wofi.nix - ./programs/wpaperd.nix ./programs/xmobar.nix ./programs/xplr.nix ./programs/yambar.nix @@ -302,6 +306,7 @@ let ./services/cliphist.nix ./services/clipman.nix ./services/clipmenu.nix + ./services/clipse.nix ./services/comodoro.nix ./services/conky.nix ./services/copyq.nix @@ -418,7 +423,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 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/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/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/dircolors.nix b/modules/programs/dircolors.nix index 91aaff41f..240be4a27 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.initExtraBeforeCompInit = mkIf cfg.enableZshIntegration '' + 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/earthly.nix b/modules/programs/earthly.nix new file mode 100644 index 000000000..e4e2a19f0 --- /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" { }; + + 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 = [ cfg.package ]; + + home.file.".earthly/config.yml" = lib.mkIf (cfg.settings != { }) { + source = yamlFormat.generate "earthly-config" cfg.settings; + }; + }; +} diff --git a/modules/programs/firefox.nix b/modules/programs/firefox.nix index 2a2667c35..01cab9bd8 100644 --- a/modules/programs/firefox.nix +++ b/modules/programs/firefox.nix @@ -1,17 +1,14 @@ { lib, ... }: - with lib; - let - modulePath = [ "programs" "firefox" ]; moduleName = concatStringsSep "." modulePath; mkFirefoxModule = import ./firefox/mkFirefoxModule.nix; - in { - meta.maintainers = [ maintainers.rycee hm.maintainers.bricked ]; + meta.maintainers = + [ maintainers.rycee hm.maintainers.bricked hm.maintainers.HPsaucii ]; imports = [ (mkFirefoxModule { @@ -21,25 +18,20 @@ 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"; }; }) (mkRemovedOptionModule (modulePath ++ [ "extensions" ]) '' - Extensions are now managed per-profile. That is, change from ${moduleName}.extensions = [ foo bar ]; to - ${moduleName}.profiles.myprofile.extensions = [ foo bar ];'') + ${moduleName}.profiles.myprofile.extensions.packages = [ foo bar ];'') (mkRemovedOptionModule (modulePath ++ [ "enableAdobeFlash" ]) "Support for this option has been removed.") (mkRemovedOptionModule (modulePath ++ [ "enableGoogleTalk" ]) diff --git a/modules/programs/firefox/mkFirefoxModule.nix b/modules/programs/firefox/mkFirefoxModule.nix index 76954dd9c..ce690801e 100644 --- a/modules/programs/firefox/mkFirefoxModule.nix +++ b/modules/programs/firefox/mkFirefoxModule.nix @@ -1,13 +1,9 @@ { modulePath, name, description ? null, wrappedPackageName ? null , unwrappedPackageName ? null, platforms, visible ? false -, enableBookmarks ? true }: - +, enableBookmarks ? true, }: { config, lib, pkgs, ... }: - with lib; - let - inherit (pkgs.stdenv.hostPlatform) isDarwin; appName = name; @@ -34,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}"; @@ -77,11 +56,13 @@ let else builtins.toJSON pref); - mkUserJs = prePrefs: prefs: extraPrefs: bookmarks: + mkUserJs = prePrefs: prefs: extraPrefs: bookmarks: extensions: let prefs' = lib.optionalAttrs ([ ] != bookmarks) { "browser.bookmarks.file" = toString (browserBookmarksFile bookmarks); "browser.places.importBookmarksHTML" = true; + } // lib.optionalAttrs (extensions != { }) { + "extensions.webextensions.ExtensionStorageIDB.enabled" = false; } // prefs; in '' // Generated by Home Manager. @@ -218,7 +199,6 @@ let # The configuration expected by the Firefox wrapper builder. bcfg = setAttrByPath [ browserName ] fcfg; - in if package == null then null else if isDarwin then @@ -227,10 +207,10 @@ 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 { }; - in { options = setAttrByPath modulePath { enable = mkOption { @@ -242,7 +222,7 @@ in { optionalString (description != null) " ${description}" } ${optionalString (!visible) - "See `programs.firefox` for more configuration options."} + "See `${moduleName}` for more configuration options."} ''; }; @@ -300,11 +280,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."; @@ -319,7 +295,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 = [ ]; @@ -327,7 +303,7 @@ in { Additional packages containing native messaging hosts that should be made available to ${appName} extensions. ''; - }); + }; finalPackage = mkOption { inherit visible; @@ -667,37 +643,125 @@ in { for more information. ''; }; - extensions = mkOption { - type = types.listOf types.package; - default = [ ]; - example = literalExpression '' - with pkgs.nur.repos.rycee.firefox-addons; [ - privacy-badger - ] - ''; + type = types.coercedTo (types.listOf types.package) (packages: { + packages = mkIf (builtins.length packages > 0) (warn '' + In order to support declarative extension configuration, + extension installation has been moved from + ${moduleName}.profiles..extensions + to + ${moduleName}.profiles..extensions.packages + '' packages); + }) (types.submodule { + options = { + packages = mkOption { + type = types.listOf types.package; + default = [ ]; + example = literalExpression '' + with pkgs.nur.repos.rycee.firefox-addons; [ + privacy-badger + ] + ''; + description = '' + List of ${name} add-on packages to install for this profile. + Some pre-packaged add-ons are accessible from the Nix User Repository. + Once you have NUR installed run + + ```console + $ nix-env -f '' -qaP -A nur.repos.rycee.firefox-addons + ``` + + to list the available ${name} add-ons. + + Note that it is necessary to manually enable these extensions + inside ${name} after the first installation. + + To automatically enable extensions add + `"extensions.autoDisableScopes" = 0;` + to + [{option}`${moduleName}.profiles..settings`](#opt-${moduleName}.profiles._name_.settings) + ''; + }; + + force = mkOption { + description = '' + Whether to override all previous firefox settings. + + This is required when using `settings`. + ''; + default = false; + example = true; + type = types.bool; + }; + + settings = mkOption { + default = { }; + example = literalExpression '' + { + # Example with uBlock origin's extensionID + "uBlock0@raymondhill.net".settings = { + selectedFilterLists = [ + "ublock-filters" + "ublock-badware" + "ublock-privacy" + "ublock-unbreak" + "ublock-quick-fixes" + ]; + }; + + # Example with Stylus' UUID-form extensionID + "{7a7a4a92-a2a0-41d1-9fd7-1e92480d612d}".settings = { + dbInChromeStorage = true; # required for Stylus + } + } + ''; + description = '' + Attribute set of options for each extension. + The keys of the attribute set consist of the ID of the extension + or its UUID wrapped in curly braces. + ''; + type = types.attrsOf (types.submodule { + options = { + settings = mkOption { + type = types.attrsOf jsonFormat.type; + description = + "Json formatted options for the specified extensionID"; + }; + force = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Forcibly override any existing configuration for + this extension. + ''; + }; + }; + }); + }; + }; + }); + default = { }; description = '' - List of ${appName} add-on packages to install for this profile. - Some pre-packaged add-ons are accessible from the - [Nix User Repository](https://github.com/nix-community/NUR). - Once you have NUR installed run - - ```console - $ nix-env -f '' -qaP -A nur.repos.rycee.firefox-addons - ``` - - to list the available ${appName} add-ons. - - Note that it is necessary to manually enable these extensions - inside ${appName} after the first installation. - - To automatically enable extensions add - `"extensions.autoDisableScopes" = 0;` - to - [{option}`${moduleName}.profiles..settings`](#opt-${moduleName}.profiles._name_.settings) + Submodule for installing and configuring extensions. + ''; + example = literalExpression '' + { + packages = with pkgs.nur.repos.rycee.firefox-addons; [ + ublock-origin + ]; + settings."uBlock0@raymondhill.net".settings = { + selectedFilterLists = [ + "ublock-filters" + "ublock-badware" + "ublock-privacy" + "ublock-unbreak" + "ublock-quick-fixes" + ]; + }; + } ''; }; - }; })); default = { }; @@ -715,6 +779,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 ({ @@ -748,7 +820,7 @@ in { { assertion = cfg.languagePacks == [ ] || cfg.package != null; message = '' - 'programs.firefox.languagePacks' requires 'programs.firefox.package' + '${moduleName}.languagePacks' requires '${moduleName}.package' to be set to a non-null value. ''; } @@ -756,67 +828,93 @@ in { (mkNoDuplicateAssertion cfg.profiles "profile") ] ++ (mapAttrsToList (_: profile: mkNoDuplicateAssertion profile.containers "container") - cfg.profiles); + 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); 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: { - "${profilesPath}/${profile.path}/.keep".text = ""; + }] ++ 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; }; + "${profilesPath}/${profile.path}/chrome/userChrome.css" = + mkIf (profile.userChrome != "") { text = profile.userChrome; }; - "${profilesPath}/${profile.path}/chrome/userContent.css" = - mkIf (profile.userContent != "") { text = profile.userContent; }; + "${profilesPath}/${profile.path}/chrome/userContent.css" = + mkIf (profile.userContent != "") { text = profile.userContent; }; - "${profilesPath}/${profile.path}/user.js" = mkIf (profile.preConfig != "" - || profile.settings != { } || profile.extraConfig != "" - || profile.bookmarks != [ ]) { - text = mkUserJs profile.preConfig profile.settings profile.extraConfig - profile.bookmarks; - }; + "${profilesPath}/${profile.path}/user.js" = mkIf (profile.preConfig + != "" || profile.settings != { } || profile.extraConfig != "" + || profile.bookmarks != [ ]) { + text = + mkUserJs profile.preConfig profile.settings profile.extraConfig + profile.bookmarks profile.extensions.settings; + }; - "${profilesPath}/${profile.path}/containers.json" = - mkIf (profile.containers != { }) { - text = mkContainersJson profile.containers; - force = profile.containersForce; - }; + "${profilesPath}/${profile.path}/containers.json" = + mkIf (profile.containers != { }) { + text = mkContainersJson profile.containers; + force = profile.containersForce; + }; - "${profilesPath}/${profile.path}/search.json.mozlz4" = - mkIf (profile.search.enable) { - enable = profile.search.enable; - force = profile.search.force; - source = profile.search.file; - }; + "${profilesPath}/${profile.path}/search.json.mozlz4" = + mkIf (profile.search.enable) { + enable = profile.search.enable; + force = profile.search.force; + source = profile.search.file; + }; - "${profilesPath}/${profile.path}/extensions" = - mkIf (profile.extensions != [ ]) { - source = let - extensionsEnvPkg = pkgs.buildEnv { - name = "hm-firefox-extensions"; - paths = profile.extensions; - }; - in "${extensionsEnvPkg}/share/mozilla/${extensionPath}"; - recursive = true; - force = true; - }; - })); + "${profilesPath}/${profile.path}/extensions" = + mkIf (profile.extensions.packages != [ ]) { + source = let + extensionsEnvPkg = pkgs.buildEnv { + name = "hm-firefox-extensions"; + paths = profile.extensions.packages; + }; + in "${extensionsEnvPkg}/share/mozilla/${extensionPath}"; + recursive = true; + force = true; + }; + }] ++ + # Add extension settings as separate attributes + optional (profile.extensions.settings != { }) (mkMerge (mapAttrsToList + (name: settingConfig: { + "${profilesPath}/${profile.path}/browser-extension-data/${name}/storage.js" = + { + force = settingConfig.force; + text = generators.toJSON { } settingConfig.settings; + }; + }) profile.extensions.settings))))); } // setAttrByPath modulePath { finalPackage = wrapPackage cfg.package; diff --git a/modules/programs/fish.nix b/modules/programs/fish.nix index 02141042d..1fb313a86 100644 --- a/modules/programs/fish.nix +++ b/modules/programs/fish.nix @@ -66,7 +66,7 @@ let }; onEvent = mkOption { - type = with types; nullOr str; + type = with types; nullOr (either str (listOf str)); default = null; description = '' Tells fish to run this function when the specified named event is @@ -511,7 +511,7 @@ in { mods = with def; modifierStr "description" description ++ modifierStr "wraps" wraps - ++ modifierStr "on-event" onEvent + ++ lib.concatMap (modifierStr "on-event") (lib.toList onEvent) ++ modifierStr "on-variable" onVariable ++ modifierStr "on-job-exit" onJobExit ++ modifierStr "on-process-exit" onProcessExit 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/ghostty.nix b/modules/programs/ghostty.nix index c0fe86208..383472efc 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 { diff --git a/modules/programs/git.nix b/modules/programs/git.nix index fa652258c..76b1b9441 100644 --- a/modules/programs/git.nix +++ b/modules/programs/git.nix @@ -411,6 +411,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 +457,7 @@ in { cfg.diff-so-fancy.enable cfg.difftastic.enable cfg.diff-highlight.enable + cfg.riff.enable ]; in count id enabled <= 1; message = @@ -496,7 +520,7 @@ in { format = if (versionOlder config.home.stateVersion "25.05") then (mkOptionDefault "openpgp") else - null; + (mkOptionDefault null); signer = let defaultSigners = { openpgp = getExe config.programs.gpg.package; @@ -678,5 +702,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/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/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..94fc83573 --- /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" { }; + + 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 = [ cfg.package ]; + + file.".jqp.yaml" = lib.mkIf (cfg.settings != { }) { + source = yamlFormat.generate "jqp-config" cfg.settings; + }; + }; + }; +} diff --git a/modules/programs/kitty.nix b/modules/programs/kitty.nix index 04dada1fa..cc7e7b4dc 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 diff --git a/modules/programs/librewolf.nix b/modules/programs/librewolf.nix index 0d2aec3b2..6b5e20894 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; diff --git a/modules/programs/mise.nix b/modules/programs/mise.nix index e0d1b1c8b..67b0a4b57 100644 --- a/modules/programs/mise.nix +++ b/modules/programs/mise.nix @@ -21,6 +21,7 @@ in { "enableBashIntegration" "enableZshIntegration" "enableFishIntegration" + "enableNushellIntegration" "settings" ]; @@ -39,6 +40,9 @@ in { enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; }; + enableNushellIntegration = + lib.hm.shell.mkNushellIntegrationOption { inherit config; }; + globalConfig = mkOption { type = tomlFormat.type; default = { }; @@ -103,6 +107,16 @@ in { fish.interactiveShellInit = mkIf cfg.enableFishIntegration '' ${getExe cfg.package} activate fish | source ''; + + nushell = mkIf cfg.enableNushellIntegration { + extraEnv = '' + let mise_path = $nu.default-config-dir | path join mise.nu + ^mise activate nu | save $mise_path --force + ''; + extraConfig = '' + use ($nu.default-config-dir | path join mise.nu) + ''; + }; }; }; } 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/nh.nix b/modules/programs/nh.nix index cb3d85e50..7e6e993fd 100644 --- a/modules/programs/nh.nix +++ b/modules/programs/nh.nix @@ -52,15 +52,11 @@ in { }; config = { - warnings = lib.optionals - (osConfig != null && !(cfg.clean.enable -> !osConfig.nix.gc.automatic)) [ - "programs.nh.clean.enable and nix.gc.automatic (system-wide in configuration.nix) are both enabled. Please use one or the other to avoid conflict." - ]; - - assertions = [{ - assertion = (cfg.flake != null) -> !(lib.hasSuffix ".nix" cfg.flake); - message = "nh.flake must be a directory, not a nix file"; - }]; + warnings = (lib.optional + (cfg.clean.enable && osConfig != null && osConfig.nix.gc.automatic) + "programs.nh.clean.enable and nix.gc.automatic (system-wide in configuration.nix) are both enabled. Please use one or the other to avoid conflict.") + ++ (lib.optional (cfg.clean.enable && config.nix.gc.automatic) + "programs.nh.clean.enable and nix.gc.automatic (Home-Manager) are both enabled. Please use one or the other to avoid conflict."); home = lib.mkIf cfg.enable { packages = [ cfg.package ]; 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/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/thunderbird.nix b/modules/programs/thunderbird.nix index 84710207c..8d9460996 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. @@ -158,6 +177,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 +208,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 = { }; @@ -400,6 +448,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 +463,17 @@ in { mkIf (profile.userContent != "") { text = profile.userContent; }; "${thunderbirdProfilesPath}/${name}/user.js" = let - accounts = filter (a: + emailAccounts = filter (a: a.thunderbird.profiles == [ ] || any (p: p == name) a.thunderbird.profiles) 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 +491,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; }; 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/vinegar.nix b/modules/programs/vinegar.nix new file mode 100644 index 000000000..5cbf672e9 --- /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" { }; + + 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 = [ 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..da8032a40 100644 --- a/modules/programs/vscode.nix +++ b/modules/programs/vscode.nix @@ -32,66 +32,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 +163,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,45 +190,207 @@ 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" + + if [ -f "$file" ]; then + existing_profiles=$(jq '.userDataProfiles // [] | map({ (.name): .location }) | add // {}' "$file") + file_write="" + profiles=(${ + escapeShellArgs + (flatten (mapAttrsToList (n: v: n) allProfilesExceptDefault)) + }) + + 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 + + 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") { + 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" && 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; + text = extensionJson defaultProfile.extensions; onChange = '' run rm $VERBOSE_ARG -f ${extensionPath}/{extensions.json,.init-default-profile-extensions} verboseEcho "Regenerating VSCode extensions.json" @@ -271,25 +402,14 @@ in { "${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" && 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/waybar.nix b/modules/programs/waybar.nix index 48a7fa5f7..0d7294d03 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; @@ -324,6 +335,8 @@ in { ExecReload = "${pkgs.coreutils}/bin/kill -SIGUSR2 $MAINPID"; Restart = "on-failure"; KillMode = "mixed"; + } // optionalAttrs cfg.systemd.enableInspect { + Environment = [ "GTK_DEBUG=interactive" ]; }; Install.WantedBy = 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/services/clipse.nix b/modules/services/clipse.nix new file mode 100644 index 000000000..f00359c85 --- /dev/null +++ b/modules/services/clipse.nix @@ -0,0 +1,166 @@ +{ 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" { }; + + 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 = [ 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 { + 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/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/mako.nix b/modules/services/mako.nix index e3298d837..df6532274 100644 --- a/modules/services/mako.nix +++ b/modules/services/mako.nix @@ -33,6 +33,15 @@ in { ''; }; + maxHistory = mkOption { + default = 5; + type = types.nullOr types.int; + description = '' + Set maximum number of expired notifications to keep in the history + buffer. Set 0 to disable history. + ''; + }; + sort = mkOption { default = "-time"; type = @@ -315,6 +324,7 @@ in { ''; text = '' ${optionalInteger "max-visible" cfg.maxVisible} + ${optionalInteger "max-history" cfg.maxHistory} ${optionalString "sort" cfg.sort} ${optionalString "output" cfg.output} ${optionalString "layer" cfg.layer} 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/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/screen-locker.nix b/modules/services/screen-locker.nix index 085573f8a..b552e1ba4 100644 --- a/modules/services/screen-locker.nix +++ b/modules/services/screen-locker.nix @@ -127,6 +127,7 @@ in { ExecStart = concatStringsSep " " ([ "${cfg.xss-lock.package}/bin/xss-lock" "-s \${XDG_SESSION_ID}" ] ++ cfg.xss-lock.extraOptions ++ [ "-- ${cfg.lockCmd}" ]); + Restart = "always"; }; }; } @@ -153,6 +154,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/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/wpaperd.nix b/modules/services/wpaperd.nix new file mode 100644 index 000000000..120cb370c --- /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" { }; + + 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 = [ cfg.package ]; + + xdg.configFile = { + "wpaperd/wallpaper.toml" = mkIf (cfg.settings != { }) { + source = tomlFormat.generate "wpaperd-wallpaper" cfg.settings; + }; + }; + + systemd.user.services.wpaperd = { + 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/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/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/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 e998d2b1a..7ab05b8a4 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -146,6 +146,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 +171,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 @@ -243,6 +245,7 @@ in import nmtSrc { ./modules/programs/translate-shell ./modules/programs/vifm ./modules/programs/vim-vint + ./modules/programs/vinegar ./modules/programs/vscode ./modules/programs/watson ./modules/programs/wezterm @@ -267,6 +270,7 @@ in import nmtSrc { ./modules/services/yubikey-agent-darwin ./modules/targets-darwin ] ++ lib.optionals isLinux [ + ./modules/config/home-cursor ./modules/config/i18n ./modules/i18n/input-method ./modules/misc/debug @@ -285,8 +289,10 @@ in import nmtSrc { ./modules/programs/boxxy ./modules/programs/cavalier ./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,6 +312,7 @@ 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 @@ -313,7 +320,6 @@ in import nmtSrc { ./modules/programs/waybar ./modules/programs/wlogout ./modules/programs/wofi - ./modules/programs/wpaperd ./modules/programs/xmobar ./modules/programs/yambar ./modules/programs/yt-dlp @@ -325,6 +331,7 @@ 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 @@ -390,6 +397,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/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/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 new file mode 100644 index 000000000..08cde5452 --- /dev/null +++ b/tests/modules/config/home-cursor/default.nix @@ -0,0 +1,49 @@ +{ + # Ensure backwards compatibility with existing configs + home-cursor-legacy = { realPkgs, ... }: { + config = { + home.pointerCursor = { + 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-legacy-disabled = { ... }: { + config = { + home.pointerCursor = null; + + 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"' + ''; + }; + }; +} diff --git a/tests/modules/config/home-cursor/expected-index.theme b/tests/modules/config/home-cursor/expected-index.theme new file mode 100644 index 000000000..7ce17e0b2 --- /dev/null +++ b/tests/modules/config/home-cursor/expected-index.theme @@ -0,0 +1,3 @@ +[Icon Theme] +Name=Catppuccin Macchiato Blue +Comment=based on Volantes Cursors 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/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..10649fdf8 100644 --- a/tests/modules/misc/xdg/default-locations.nix +++ b/tests/modules/misc/xdg/default-locations.nix @@ -1,8 +1,4 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ +{ config, lib, ... }: { config = { # Test fallback behavior for stateVersion >= 20.09, which is pure. xdg.enable = lib.mkForce false; 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/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/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/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..7dca728a9 100644 --- a/tests/modules/programs/firefox/common.nix +++ b/tests/modules/programs/firefox/common.nix @@ -1,6 +1,7 @@ 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; @@ -10,6 +11,7 @@ builtins.mapAttrs (test: module: import module [ "programs" name ]) { "${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/extensions/default.nix b/tests/modules/programs/firefox/profiles/extensions/default.nix new file mode 100644 index 000000000..7f181b4fd --- /dev/null +++ b/tests/modules/programs/firefox/profiles/extensions/default.nix @@ -0,0 +1,36 @@ +modulePath: +{ config, lib, ... }: +with lib; +let + cfg = getAttrFromPath modulePath config; + + firefoxMockOverlay = import ../../setup-firefox-mock-overlay.nix modulePath; +in { + imports = [ firefoxMockOverlay ]; + + config = mkIf config.test.enableBig (setAttrByPath modulePath { + enable = true; + profiles.extensions = { + 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/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 new file mode 100644 index 000000000..225234411 --- /dev/null +++ b/tests/modules/programs/firefox/profiles/extensions/expected-storage.js @@ -0,0 +1 @@ +{"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/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/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/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/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/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/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/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/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/mise/default.nix b/tests/modules/programs/mise/default.nix index 511082a12..402e32639 100644 --- a/tests/modules/programs/mise/default.nix +++ b/tests/modules/programs/mise/default.nix @@ -4,4 +4,5 @@ mise-bash-integration = ./bash-integration.nix; mise-zsh-integration = ./zsh-integration.nix; mise-fish-integration = ./fish-integration.nix; + mise-nushell-integration = ./nushell-integration.nix; } diff --git a/tests/modules/programs/mise/nushell-integration.nix b/tests/modules/programs/mise/nushell-integration.nix new file mode 100644 index 000000000..926df987e --- /dev/null +++ b/tests/modules/programs/mise/nushell-integration.nix @@ -0,0 +1,21 @@ +{ config, ... }: { + programs = { + mise = { + package = config.lib.test.mkStubPackage { name = "mise"; }; + enable = true; + enableNushellIntegration = true; + }; + + nushell.enable = true; + }; + + nmt.script = '' + assertFileContains home-files/.config/nushell/env.nu \ + ' + let mise_path = $nu.default-config-dir | path join mise.nu + ^mise activate nu | save $mise_path --force + ' + assertFileContains home-files/.config/nushell/config.nu \ + 'use ($nu.default-config-dir | path join mise.nu)' + ''; +} 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/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/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/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/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/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-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-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..961b91359 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 = { @@ -41,6 +41,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 +58,8 @@ extraConfig = '' user_pref("mail.html_compose", false); ''; + + feedAccounts.rss = { }; }; second.settings = { @@ -69,7 +75,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"; 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..7d024fed3 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/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/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/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/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/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/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/screen-locker/basic-configuration.nix b/tests/modules/services/screen-locker/basic-configuration.nix index 855370d2b..e92a4a9f1 100644 --- a/tests/modules/services/screen-locker/basic-configuration.nix +++ b/tests/modules/services/screen-locker/basic-configuration.nix @@ -19,7 +19,9 @@ assertFileExists $xssService assertFileRegex $xssService 'ExecStart=.*/bin/xss-lock.*-test.*i3lock -n -c AA0000' + 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/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/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/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/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-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; }; }