1
0
Fork 0
mirror of https://github.com/nix-community/home-manager.git synced 2025-11-08 19:46:05 +01:00

treewide: reformat nixfmt-rfc-style

Reformat repository using new nixfmt-rfc-style.
This commit is contained in:
Austin Horstman 2025-04-07 16:11:29 -05:00
parent 5df48c4255
commit cba2f9ce95
1051 changed files with 37028 additions and 26594 deletions

View file

@ -1,4 +1,6 @@
{ pkgs ? import <nixpkgs> { } }: {
pkgs ? import <nixpkgs> { },
}:
let let
path = builtins.path { path = builtins.path {
@ -6,12 +8,17 @@ let
name = "home-manager-source"; name = "home-manager-source";
}; };
in rec { in
docs = let releaseInfo = pkgs.lib.importJSON ./release.json; rec {
in with import ./docs { docs =
let
releaseInfo = pkgs.lib.importJSON ./release.json;
in
with import ./docs {
inherit pkgs; inherit pkgs;
inherit (releaseInfo) release isReleaseBranch; inherit (releaseInfo) release isReleaseBranch;
}; { };
{
inherit manPages jsonModuleMaintainers; inherit manPages jsonModuleMaintainers;
inherit (manual) html htmlOpenTool; inherit (manual) html htmlOpenTool;
@ -20,8 +27,7 @@ in rec {
home-manager = pkgs.callPackage ./home-manager { inherit path; }; home-manager = pkgs.callPackage ./home-manager { inherit path; };
install = install = pkgs.callPackage ./home-manager/install.nix { inherit home-manager; };
pkgs.callPackage ./home-manager/install.nix { inherit home-manager; };
nixos = import ./nixos; nixos = import ./nixos;
lib = import ./lib { inherit (pkgs) lib; }; lib = import ./lib { inherit (pkgs) lib; };

View file

@ -1,9 +1,12 @@
{ pkgs {
pkgs,
# Note, this should be "the standard library" + HM extensions. # Note, this should be "the standard library" + HM extensions.
, lib ? import ../modules/lib/stdlib-extended.nix pkgs.lib lib ? import ../modules/lib/stdlib-extended.nix pkgs.lib,
, release, isReleaseBranch }: release,
isReleaseBranch,
}:
let let
@ -19,86 +22,124 @@ let
# Caveat: even if the package is reached by a different means, the # Caveat: even if the package is reached by a different means, the
# path above will be shown and not e.g. # path above will be shown and not e.g.
# `${config.services.foo.package}`. # `${config.services.foo.package}`.
scrubDerivations = prefixPath: attrs: scrubDerivations =
prefixPath: attrs:
let let
scrubDerivation = name: value: scrubDerivation =
let pkgAttrName = prefixPath + "." + name; name: value:
in if lib.isAttrs value then let
pkgAttrName = prefixPath + "." + name;
in
if lib.isAttrs value then
scrubDerivations pkgAttrName value scrubDerivations pkgAttrName value
// lib.optionalAttrs (lib.isDerivation value) { // lib.optionalAttrs (lib.isDerivation value) {
outPath = "\${${pkgAttrName}}"; outPath = "\${${pkgAttrName}}";
} }
else else
value; value;
in lib.mapAttrs scrubDerivation attrs; in
lib.mapAttrs scrubDerivation attrs;
# Make sure the used package is scrubbed to avoid actually # Make sure the used package is scrubbed to avoid actually
# instantiating derivations. # instantiating derivations.
scrubbedPkgsModule = { scrubbedPkgsModule = {
imports = [{ imports = [
{
_module.args = { _module.args = {
pkgs = lib.mkForce (scrubDerivations "pkgs" pkgs); pkgs = lib.mkForce (scrubDerivations "pkgs" pkgs);
pkgs_i686 = lib.mkForce { }; pkgs_i686 = lib.mkForce { };
}; };
}]; }
];
}; };
dontCheckDefinitions = { _module.check = false; }; dontCheckDefinitions = {
_module.check = false;
};
gitHubDeclaration = user: repo: subpath: gitHubDeclaration =
let urlRef = if isReleaseBranch then "release-${release}" else "master"; user: repo: subpath:
in { let
urlRef = if isReleaseBranch then "release-${release}" else "master";
in
{
url = "https://github.com/${user}/${repo}/blob/${urlRef}/${subpath}"; url = "https://github.com/${user}/${repo}/blob/${urlRef}/${subpath}";
name = "<${repo}/${subpath}>"; name = "<${repo}/${subpath}>";
}; };
hmPath = toString ./..; hmPath = toString ./..;
buildOptionsDocs = args@{ modules, includeModuleSystemOptions ? true, ... }: buildOptionsDocs =
args@{
modules,
includeModuleSystemOptions ? true,
...
}:
let let
options = (lib.evalModules { options =
(lib.evalModules {
inherit modules; inherit modules;
class = "homeManager"; class = "homeManager";
}).options; }).options;
in pkgs.buildPackages.nixosOptionsDoc ({ in
options = if includeModuleSystemOptions then pkgs.buildPackages.nixosOptionsDoc (
options {
else options =
builtins.removeAttrs options [ "_module" ]; if includeModuleSystemOptions then options else builtins.removeAttrs options [ "_module" ];
transformOptions = opt: transformOptions =
opt // { opt:
opt
// {
# Clean up declaration sites to not refer to the Home Manager # Clean up declaration sites to not refer to the Home Manager
# source tree. # source tree.
declarations = map (decl: declarations = map (
decl:
if lib.hasPrefix hmPath (toString decl) then if lib.hasPrefix hmPath (toString decl) then
gitHubDeclaration "nix-community" "home-manager" gitHubDeclaration "nix-community" "home-manager" (
(lib.removePrefix "/" (lib.removePrefix hmPath (toString decl))) lib.removePrefix "/" (lib.removePrefix hmPath (toString decl))
)
else if decl == "lib/modules.nix" then else if decl == "lib/modules.nix" then
# TODO: handle this in a better way (may require upstream # TODO: handle this in a better way (may require upstream
# changes to nixpkgs) # changes to nixpkgs)
gitHubDeclaration "NixOS" "nixpkgs" decl gitHubDeclaration "NixOS" "nixpkgs" decl
else else
decl) opt.declarations; decl
) opt.declarations;
}; };
} // builtins.removeAttrs args [ "modules" "includeModuleSystemOptions" ]); }
// builtins.removeAttrs args [
"modules"
"includeModuleSystemOptions"
]
);
hmOptionsDocs = buildOptionsDocs { hmOptionsDocs = buildOptionsDocs {
modules = import ../modules/modules.nix { modules =
import ../modules/modules.nix {
inherit lib pkgs; inherit lib pkgs;
check = false; check = false;
} ++ [ scrubbedPkgsModule ]; }
++ [ scrubbedPkgsModule ];
variablelistId = "home-manager-options"; variablelistId = "home-manager-options";
}; };
nixosOptionsDocs = buildOptionsDocs { nixosOptionsDocs = buildOptionsDocs {
modules = [ ../nixos scrubbedPkgsModule dontCheckDefinitions ]; modules = [
../nixos
scrubbedPkgsModule
dontCheckDefinitions
];
includeModuleSystemOptions = false; includeModuleSystemOptions = false;
variablelistId = "nixos-options"; variablelistId = "nixos-options";
optionIdPrefix = "nixos-opt-"; optionIdPrefix = "nixos-opt-";
}; };
nixDarwinOptionsDocs = buildOptionsDocs { nixDarwinOptionsDocs = buildOptionsDocs {
modules = [ ../nix-darwin scrubbedPkgsModule dontCheckDefinitions ]; modules = [
../nix-darwin
scrubbedPkgsModule
dontCheckDefinitions
];
includeModuleSystemOptions = false; includeModuleSystemOptions = false;
variablelistId = "nix-darwin-options"; variablelistId = "nix-darwin-options";
optionIdPrefix = "nix-darwin-opt-"; optionIdPrefix = "nix-darwin-opt-";
@ -108,11 +149,15 @@ let
revision = "release-${release-config.release}"; revision = "release-${release-config.release}";
# Generate the `man home-configuration.nix` package # Generate the `man home-configuration.nix` package
home-configuration-manual = home-configuration-manual =
pkgs.runCommand "home-configuration-reference-manpage" { pkgs.runCommand "home-configuration-reference-manpage"
nativeBuildInputs = {
[ pkgs.buildPackages.installShellFiles pkgs.nixos-render-docs ]; nativeBuildInputs = [
pkgs.buildPackages.installShellFiles
pkgs.nixos-render-docs
];
allowedReferences = [ "out" ]; allowedReferences = [ "out" ];
} '' }
''
# Generate manpages. # Generate manpages.
mkdir -p $out/share/man/man5 mkdir -p $out/share/man/man5
mkdir -p $out/share/man/man1 mkdir -p $out/share/man/man1
@ -135,13 +180,17 @@ let
}; };
html = home-manager-manual; html = home-manager-manual;
htmlOpenTool = pkgs.callPackage ./html-open-tool.nix { } { inherit html; }; htmlOpenTool = pkgs.callPackage ./html-open-tool.nix { } { inherit html; };
in { in
{
options = { options = {
# TODO: Use `hmOptionsDocs.optionsJSON` directly once upstream # TODO: Use `hmOptionsDocs.optionsJSON` directly once upstream
# `nixosOptionsDoc` is more customizable. # `nixosOptionsDoc` is more customizable.
json = pkgs.runCommand "options.json" { json =
pkgs.runCommand "options.json"
{
meta.description = "List of Home Manager options in JSON format"; meta.description = "List of Home Manager options in JSON format";
} '' }
''
mkdir -p $out/{share/doc,nix-support} mkdir -p $out/{share/doc,nix-support}
cp -a ${hmOptionsDocs.optionsJSON}/share/doc/nixos $out/share/doc/home-manager cp -a ${hmOptionsDocs.optionsJSON}/share/doc/nixos $out/share/doc/home-manager
substitute \ substitute \
@ -158,13 +207,18 @@ in {
manual = { inherit html htmlOpenTool; }; manual = { inherit html htmlOpenTool; };
# Unstable, mainly for CI. # Unstable, mainly for CI.
jsonModuleMaintainers = pkgs.writeText "hm-module-maintainers.json" (let jsonModuleMaintainers = pkgs.writeText "hm-module-maintainers.json" (
let
result = lib.evalModules { result = lib.evalModules {
modules = import ../modules/modules.nix { modules =
import ../modules/modules.nix {
inherit lib pkgs; inherit lib pkgs;
check = false; check = false;
} ++ [ scrubbedPkgsModule ]; }
++ [ scrubbedPkgsModule ];
class = "homeManager"; class = "homeManager";
}; };
in builtins.toJSON result.config.meta.maintainers); in
builtins.toJSON result.config.meta.maintainers
);
} }

View file

@ -9,7 +9,12 @@
}; };
}; };
outputs = { self, nixpkgs, scss-reset }: outputs =
{
self,
nixpkgs,
scss-reset,
}:
let let
supportedSystems = [ supportedSystems = [
"aarch64-darwin" "aarch64-darwin"
@ -28,7 +33,12 @@
p-build = pkgs.writeShellScriptBin "p-build" '' p-build = pkgs.writeShellScriptBin "p-build" ''
set -euo pipefail set -euo pipefail
export PATH=${lib.makeBinPath [ pkgs.coreutils pkgs.rsass ]} export PATH=${
lib.makeBinPath [
pkgs.coreutils
pkgs.rsass
]
}
tmpfile=$(mktemp -d) tmpfile=$(mktemp -d)
trap "rm -r $tmpfile" EXIT trap "rm -r $tmpfile" EXIT
@ -42,20 +52,25 @@
}; };
releaseInfo = lib.importJSON ../release.json; releaseInfo = lib.importJSON ../release.json;
in { in
devShells = forAllSystems (system: {
devShells = forAllSystems (
system:
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
fpkgs = flakePkgs pkgs; fpkgs = flakePkgs pkgs;
in { in
{
default = pkgs.mkShell { default = pkgs.mkShell {
name = "hm-docs"; name = "hm-docs";
packages = [ fpkgs.p-build ]; packages = [ fpkgs.p-build ];
}; };
}); }
);
# Expose the docs outputs # Expose the docs outputs
packages = forAllSystems (system: packages = forAllSystems (
system:
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
docs = import ./default.nix { docs = import ./default.nix {
@ -63,10 +78,12 @@
release = releaseInfo.release; release = releaseInfo.release;
isReleaseBranch = releaseInfo.isReleaseBranch; isReleaseBranch = releaseInfo.isReleaseBranch;
}; };
in { in
{
inherit (docs) manPages jsonModuleMaintainers; inherit (docs) manPages jsonModuleMaintainers;
inherit (docs.manual) html htmlOpenTool; inherit (docs.manual) html htmlOpenTool;
inherit (docs.options) json; inherit (docs.options) json;
}); }
);
}; };
} }

View file

@ -1,7 +1,15 @@
{ stdenv, lib, documentation-highlighter, revision, home-manager-options {
, nixos-render-docs }: stdenv,
let outputPath = "share/doc/home-manager"; lib,
in stdenv.mkDerivation { documentation-highlighter,
revision,
home-manager-options,
nixos-render-docs,
}:
let
outputPath = "share/doc/home-manager";
in
stdenv.mkDerivation {
name = "home-manager-manual"; name = "home-manager-manual";
nativeBuildInputs = [ nixos-render-docs ]; nativeBuildInputs = [ nixos-render-docs ];
@ -61,5 +69,7 @@ in stdenv.mkDerivation {
passthru = { inherit home-manager-options; }; passthru = { inherit home-manager-options; };
meta = { maintainers = [ lib.maintainers.considerate ]; }; meta = {
maintainers = [ lib.maintainers.considerate ];
};
} }

View file

@ -1,6 +1,14 @@
{ writeShellScriptBin, makeDesktopItem, symlinkJoin }: {
{ html, pathName ? "home-manager", projectName ? pathName writeShellScriptBin,
, name ? "${pathName}-help" }: makeDesktopItem,
symlinkJoin,
}:
{
html,
pathName ? "home-manager",
projectName ? pathName,
name ? "${pathName}-help",
}:
let let
helpScript = writeShellScriptBin name '' helpScript = writeShellScriptBin name ''
set -euo pipefail set -euo pipefail
@ -30,7 +38,11 @@ let
exec = "${helpScript}/bin/${name}"; exec = "${helpScript}/bin/${name}";
categories = [ "System" ]; categories = [ "System" ];
}; };
in symlinkJoin { in
symlinkJoin {
inherit name; inherit name;
paths = [ helpScript desktopItem ]; paths = [
helpScript
desktopItem
];
} }

View file

@ -1,6 +1,18 @@
{ lib, flake-parts-lib, moduleLocation, ... }: {
let inherit (lib) toString mapAttrs mkOption types; lib,
in { flake-parts-lib,
moduleLocation,
...
}:
let
inherit (lib)
toString
mapAttrs
mkOption
types
;
in
{
options = { options = {
flake = flake-parts-lib.mkSubmoduleOptions { flake = flake-parts-lib.mkSubmoduleOptions {
homeConfigurations = mkOption { homeConfigurations = mkOption {
@ -17,11 +29,13 @@ in {
homeModules = mkOption { homeModules = mkOption {
type = types.lazyAttrsOf types.deferredModule; type = types.lazyAttrsOf types.deferredModule;
default = { }; default = { };
apply = mapAttrs (k: v: { apply = mapAttrs (
k: v: {
_class = "homeManager"; _class = "homeManager";
_file = "${toString moduleLocation}#homeModules.${k}"; _file = "${toString moduleLocation}#homeModules.${k}";
imports = [ v ]; imports = [ v ];
}); }
);
description = '' description = ''
Home Manager modules. Home Manager modules.

View file

@ -10,7 +10,13 @@
}; };
}; };
outputs = { self, nixpkgs, treefmt-nix, ... }: outputs =
{
self,
nixpkgs,
treefmt-nix,
...
}:
{ {
nixosModules = rec { nixosModules = rec {
home-manager = ./nixos; home-manager = ./nixos;
@ -44,7 +50,9 @@
}; };
lib = import ./lib { inherit (nixpkgs) lib; }; lib = import ./lib { inherit (nixpkgs) lib; };
} // (let }
// (
let
forAllSystems = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed; forAllSystems = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed;
treefmtEval = forAllSystems ( treefmtEval = forAllSystems (
@ -54,15 +62,18 @@
programs = { programs = {
nixfmt.enable = true; nixfmt.enable = true;
}; };
}); }
in { );
in
{
checks = forAllSystems (system: { checks = forAllSystems (system: {
formatting = treefmtEval.${system}.config.build.check self; formatting = treefmtEval.${system}.config.build.check self;
}); });
formatter = forAllSystems (system: treefmtEval.${system}.config.build.wrapper); formatter = forAllSystems (system: treefmtEval.${system}.config.build.wrapper);
packages = forAllSystems (system: packages = forAllSystems (
system:
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
releaseInfo = nixpkgs.lib.importJSON ./release.json; releaseInfo = nixpkgs.lib.importJSON ./release.json;
@ -71,7 +82,8 @@
inherit (releaseInfo) release isReleaseBranch; inherit (releaseInfo) release isReleaseBranch;
}; };
hmPkg = pkgs.callPackage ./home-manager { path = "${self}"; }; hmPkg = pkgs.callPackage ./home-manager { path = "${self}"; };
in { in
{
default = hmPkg; default = hmPkg;
home-manager = hmPkg; home-manager = hmPkg;
@ -80,6 +92,8 @@
docs-json = docs.options.json; docs-json = docs.options.json;
docs-jsonModuleMaintainers = docs.jsonModuleMaintainers; docs-jsonModuleMaintainers = docs.jsonModuleMaintainers;
docs-manpages = docs.manPages; docs-manpages = docs.manPages;
}); }
}); );
}
);
} }

View file

@ -2,46 +2,70 @@
# file is considered internal and the exported fields may change without # file is considered internal and the exported fields may change without
# warning. # warning.
{ newsJsonFile, newsReadIdsFile ? null }: {
newsJsonFile,
newsReadIdsFile ? null,
}:
let let
inherit (builtins) inherit (builtins)
concatStringsSep filter hasAttr isString length readFile replaceStrings sort concatStringsSep
split; filter
hasAttr
isString
length
readFile
replaceStrings
sort
split
;
newsJson = builtins.fromJSON (builtins.readFile newsJsonFile); newsJson = builtins.fromJSON (builtins.readFile newsJsonFile);
# Sorted and relevant entries. # Sorted and relevant entries.
relevantEntries = relevantEntries = sort (a: b: a.time > b.time) (filter (e: e.condition) newsJson.entries);
sort (a: b: a.time > b.time) (filter (e: e.condition) newsJson.entries);
newsReadIds = if newsReadIdsFile == null then newsReadIds =
if newsReadIdsFile == null then
{ } { }
else else
let ids = filter isString (split "\n" (readFile newsReadIdsFile)); let
in builtins.listToAttrs (map (id: { ids = filter isString (split "\n" (readFile newsReadIdsFile));
in
builtins.listToAttrs (
map (id: {
name = id; name = id;
value = null; value = null;
}) ids); }) ids
);
newsIsRead = entry: hasAttr entry.id newsReadIds; newsIsRead = entry: hasAttr entry.id newsReadIds;
newsUnread = let pred = entry: entry.condition && !newsIsRead entry; newsUnread =
in filter pred relevantEntries; let
pred = entry: entry.condition && !newsIsRead entry;
in
filter pred relevantEntries;
prettyTime = t: replaceStrings [ "T" "+00:00" ] [ " " "" ] t; prettyTime = t: replaceStrings [ "T" "+00:00" ] [ " " "" ] t;
layoutNews = entries: layoutNews =
entries:
let let
mkTextEntry = entry: mkTextEntry =
let flag = if newsIsRead entry then "read" else "unread"; entry:
in '' let
flag = if newsIsRead entry then "read" else "unread";
in
''
* ${prettyTime entry.time} [${flag}] * ${prettyTime entry.time} [${flag}]
${replaceStrings [ "\n" ] [ "\n " ] entry.message} ${replaceStrings [ "\n" ] [ "\n " ] entry.message}
''; '';
in concatStringsSep "\n\n" (map mkTextEntry entries); in
in { concatStringsSep "\n\n" (map mkTextEntry entries);
in
{
meta = { meta = {
numUnread = length newsUnread; numUnread = length newsUnread;
display = newsJson.display; display = newsJson.display;

View file

@ -1,19 +1,33 @@
{ runCommand, lib, bash, callPackage, coreutils, findutils, gettext, gnused, jq {
, less, ncurses, inetutils runCommand,
lib,
bash,
callPackage,
coreutils,
findutils,
gettext,
gnused,
jq,
less,
ncurses,
inetutils,
# used for pkgs.path for nixos-option # used for pkgs.path for nixos-option
, pkgs pkgs,
# Path to use as the Home Manager channel. # Path to use as the Home Manager channel.
, path ? null }: path ? null,
}:
let let
pathStr = if path == null then "" else path; pathStr = if path == null then "" else path;
nixos-option = pkgs.nixos-option or (callPackage nixos-option =
(pkgs.path + "/nixos/modules/installer/tools/nixos-option") { }); pkgs.nixos-option or (callPackage (pkgs.path + "/nixos/modules/installer/tools/nixos-option") { });
in runCommand "home-manager" { in
runCommand "home-manager"
{
preferLocalBuild = true; preferLocalBuild = true;
nativeBuildInputs = [ gettext ]; nativeBuildInputs = [ gettext ];
meta = { meta = {
@ -23,7 +37,8 @@ in runCommand "home-manager" {
platforms = lib.platforms.unix; platforms = lib.platforms.unix;
license = lib.licenses.mit; license = lib.licenses.mit;
}; };
} '' }
''
install -v -D -m755 ${./home-manager} $out/bin/home-manager install -v -D -m755 ${./home-manager} $out/bin/home-manager
substituteInPlace $out/bin/home-manager \ substituteInPlace $out/bin/home-manager \

View file

@ -1,18 +1,31 @@
{ pkgs ? import <nixpkgs> { }, confPath, confAttr ? null, check ? true {
, newsReadIdsFile ? null }: pkgs ? import <nixpkgs> { },
confPath,
confAttr ? null,
check ? true,
newsReadIdsFile ? null,
}:
let let
inherit (pkgs.lib) inherit (pkgs.lib)
concatMapStringsSep fileContents filter length optionalString removeSuffix concatMapStringsSep
replaceStrings splitString; fileContents
filter
length
optionalString
removeSuffix
replaceStrings
splitString
;
env = import ../modules { env = import ../modules {
configuration = if confAttr == "" || confAttr == null then configuration =
confPath if confAttr == "" || confAttr == null then confPath else (import confPath).${confAttr};
else
(import confPath).${confAttr};
pkgs = pkgs; pkgs = pkgs;
check = check; check = check;
}; };
in { inherit (env) activationPackage config; } in
{
inherit (env) activationPackage config;
}

View file

@ -8,12 +8,15 @@ let
source ${home-manager}/share/bash/home-manager.sh source ${home-manager}/share/bash/home-manager.sh
''; '';
in runCommand "home-manager-install" { in
runCommand "home-manager-install"
{
propagatedBuildInputs = [ home-manager ]; propagatedBuildInputs = [ home-manager ];
preferLocalBuild = true; preferLocalBuild = true;
shellHookOnly = true; shellHookOnly = true;
shellHook = "exec ${home-manager}/bin/home-manager init --switch --no-flake"; shellHook = "exec ${home-manager}/bin/home-manager init --switch --no-flake";
} '' }
''
${hmBashLibInit} ${hmBashLibInit}
_iError 'This derivation is not buildable, please run it using nix-shell.' _iError 'This derivation is not buildable, please run it using nix-shell.'
exit 1 exit 1

View file

@ -1,10 +1,21 @@
{ lib }: { { lib }:
{
hm = (import ../modules/lib/stdlib-extended.nix lib).hm; hm = (import ../modules/lib/stdlib-extended.nix lib).hm;
homeManagerConfiguration = { modules ? [ ], pkgs, lib ? pkgs.lib homeManagerConfiguration =
, extraSpecialArgs ? { }, check ? true {
modules ? [ ],
pkgs,
lib ? pkgs.lib,
extraSpecialArgs ? { },
check ? true,
# Deprecated: # Deprecated:
, configuration ? null, extraModules ? null, stateVersion ? null configuration ? null,
, username ? null, homeDirectory ? null, system ? null }@args: extraModules ? null,
stateVersion ? null,
username ? null,
homeDirectory ? null,
system ? null,
}@args:
let let
msgForRemovedArg = '' msgForRemovedArg = ''
The 'homeManagerConfiguration' arguments The 'homeManagerConfiguration' arguments
@ -20,7 +31,8 @@
'modules'. See the 22.11 release notes for more: https://nix-community.github.io/home-manager/release-notes.xhtml#sec-release-22.11-highlights 'modules'. See the 22.11 release notes for more: https://nix-community.github.io/home-manager/release-notes.xhtml#sec-release-22.11-highlights
''; '';
throwForRemovedArgs = v: throwForRemovedArgs =
v:
let let
used = builtins.filter (n: (args.${n} or null) != null) [ used = builtins.filter (n: (args.${n} or null) != null) [
"configuration" "configuration"
@ -30,20 +42,34 @@
"extraModules" "extraModules"
"system" "system"
]; ];
msg = msgForRemovedArg + '' msg =
msgForRemovedArg
+ ''
Deprecated args passed: '' + builtins.concatStringsSep " " used; Deprecated args passed: ''
in lib.throwIf (used != [ ]) msg v; + builtins.concatStringsSep " " used;
in
lib.throwIf (used != [ ]) msg v;
in throwForRemovedArgs (import ../modules { in
inherit pkgs lib check extraSpecialArgs; throwForRemovedArgs (
configuration = { ... }: { import ../modules {
inherit
pkgs
lib
check
extraSpecialArgs
;
configuration =
{ ... }:
{
imports = modules ++ [ { programs.home-manager.path = "${../.}"; } ]; imports = modules ++ [ { programs.home-manager.path = "${../.}"; } ];
nixpkgs = { nixpkgs = {
config = lib.mkDefault pkgs.config; config = lib.mkDefault pkgs.config;
inherit (pkgs) overlays; inherit (pkgs) overlays;
}; };
}; };
}); }
);
} }

View file

@ -4,19 +4,22 @@ let
cfg = config.accounts.calendar; cfg = config.accounts.calendar;
localModule = name: localModule =
name:
types.submodule { types.submodule {
options = { options = {
path = mkOption { path = mkOption {
type = types.str; type = types.str;
default = "${cfg.basePath}/${name}"; default = "${cfg.basePath}/${name}";
defaultText = defaultText = lib.literalExpression "accounts.calendar.basePath/name";
lib.literalExpression "accounts.calendar.basePath/name";
description = "The path of the storage."; description = "The path of the storage.";
}; };
type = mkOption { type = mkOption {
type = types.enum [ "filesystem" "singlefile" ]; type = types.enum [
"filesystem"
"singlefile"
];
default = "filesystem"; default = "filesystem";
description = "The type of the storage."; description = "The type of the storage.";
}; };
@ -41,7 +44,11 @@ let
remoteModule = types.submodule { remoteModule = types.submodule {
options = { options = {
type = mkOption { type = mkOption {
type = types.enum [ "caldav" "http" "google_calendar" ]; type = types.enum [
"caldav"
"http"
"google_calendar"
];
description = "The type of the storage."; description = "The type of the storage.";
}; };
@ -60,7 +67,10 @@ let
passwordCommand = mkOption { passwordCommand = mkOption {
type = types.nullOr (types.listOf types.str); type = types.nullOr (types.listOf types.str);
default = null; default = null;
example = [ "pass" "caldav" ]; example = [
"pass"
"caldav"
];
description = '' description = ''
A command that prints the password to standard output. A command that prints the password to standard output.
''; '';
@ -68,7 +78,9 @@ let
}; };
}; };
calendarOpts = { name, ... }: { calendarOpts =
{ name, ... }:
{
options = { options = {
name = mkOption { name = mkOption {
type = types.str; type = types.str;
@ -114,16 +126,18 @@ let
}; };
}; };
config = { name = name; }; config = {
name = name;
};
}; };
in { in
{
options.accounts.calendar = { options.accounts.calendar = {
basePath = mkOption { basePath = mkOption {
type = types.str; type = types.str;
example = ".calendar"; example = ".calendar";
apply = p: apply = p: if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
description = '' description = ''
The base directory in which to save calendars. May be a The base directory in which to save calendars. May be a
relative path, in which case it is relative the home relative path, in which case it is relative the home
@ -132,25 +146,32 @@ in {
}; };
accounts = mkOption { accounts = mkOption {
type = types.attrsOf (types.submodule [ type = types.attrsOf (
types.submodule [
calendarOpts calendarOpts
(import ../programs/vdirsyncer-accounts.nix) (import ../programs/vdirsyncer-accounts.nix)
(import ../programs/khal-accounts.nix) (import ../programs/khal-accounts.nix)
(import ../programs/khal-calendar-accounts.nix) (import ../programs/khal-calendar-accounts.nix)
]); ]
);
default = { }; default = { };
description = "List of calendars."; description = "List of calendars.";
}; };
}; };
config = lib.mkIf (cfg.accounts != { }) { config = lib.mkIf (cfg.accounts != { }) {
assertions = let assertions =
primaries = lib.catAttrs "name" let
(lib.filter (a: a.primary) (lib.attrValues cfg.accounts)); primaries = lib.catAttrs "name" (lib.filter (a: a.primary) (lib.attrValues cfg.accounts));
in [{ in
[
{
assertion = lib.length primaries <= 1; assertion = lib.length primaries <= 1;
message = "Must have at most one primary calendar account but found " message =
+ toString (lib.length primaries) + ", namely " "Must have at most one primary calendar account but found "
+ toString (lib.length primaries)
+ ", namely "
+ lib.concatStringsSep ", " primaries; + lib.concatStringsSep ", " primaries;
}]; }
];
}; };
} }

View file

@ -5,19 +5,22 @@ let
cfg = config.accounts.contact; cfg = config.accounts.contact;
localModule = name: localModule =
name:
types.submodule { types.submodule {
options = { options = {
path = mkOption { path = mkOption {
type = types.str; type = types.str;
default = "${cfg.basePath}/${name}"; default = "${cfg.basePath}/${name}";
defaultText = defaultText = lib.literalExpression "accounts.contact.basePath/name";
lib.literalExpression "accounts.contact.basePath/name";
description = "The path of the storage."; description = "The path of the storage.";
}; };
type = mkOption { type = mkOption {
type = types.enum [ "filesystem" "singlefile" ]; type = types.enum [
"filesystem"
"singlefile"
];
description = "The type of the storage."; description = "The type of the storage.";
}; };
@ -41,7 +44,11 @@ let
remoteModule = types.submodule { remoteModule = types.submodule {
options = { options = {
type = mkOption { type = mkOption {
type = types.enum [ "carddav" "http" "google_contacts" ]; type = types.enum [
"carddav"
"http"
"google_contacts"
];
description = "The type of the storage."; description = "The type of the storage.";
}; };
@ -69,7 +76,10 @@ let
passwordCommand = mkOption { passwordCommand = mkOption {
type = types.nullOr (types.listOf types.str); type = types.nullOr (types.listOf types.str);
default = null; default = null;
example = [ "pass" "caldav" ]; example = [
"pass"
"caldav"
];
description = '' description = ''
A command that prints the password to standard output. A command that prints the password to standard output.
''; '';
@ -77,7 +87,9 @@ let
}; };
}; };
contactOpts = { name, ... }: { contactOpts =
{ name, ... }:
{
options = { options = {
name = mkOption { name = mkOption {
type = types.str; type = types.str;
@ -105,15 +117,17 @@ let
}; };
}; };
config = { name = name; }; config = {
name = name;
};
}; };
in { in
{
options.accounts.contact = { options.accounts.contact = {
basePath = mkOption { basePath = mkOption {
type = types.str; type = types.str;
apply = p: apply = p: if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
description = '' description = ''
The base directory in which to save contacts. May be a The base directory in which to save contacts. May be a
relative path, in which case it is relative the home relative path, in which case it is relative the home
@ -122,12 +136,14 @@ in {
}; };
accounts = mkOption { accounts = mkOption {
type = types.attrsOf (types.submodule [ type = types.attrsOf (
types.submodule [
contactOpts contactOpts
(import ../programs/vdirsyncer-accounts.nix) (import ../programs/vdirsyncer-accounts.nix)
(import ../programs/khal-accounts.nix) (import ../programs/khal-accounts.nix)
(import ../programs/khal-contact-accounts.nix) (import ../programs/khal-contact-accounts.nix)
]); ]
);
default = { }; default = { };
description = "List of contacts."; description = "List of contacts.";
}; };

View file

@ -1,7 +1,12 @@
{ config, lib, ... }: { config, lib, ... }:
let let
inherit (lib) mkDefault mkIf mkOption types; inherit (lib)
mkDefault
mkIf
mkOption
types
;
cfg = config.accounts.email; cfg = config.accounts.email;
@ -66,7 +71,11 @@ let
}; };
showSignature = mkOption { showSignature = mkOption {
type = types.enum [ "append" "attach" "none" ]; type = types.enum [
"append"
"attach"
"none"
];
default = "none"; default = "none";
description = "Method to communicate the signature."; description = "Method to communicate the signature.";
}; };
@ -195,7 +204,9 @@ let
}; };
}; };
maildirModule = types.submodule ({ config, ... }: { maildirModule = types.submodule (
{ config, ... }:
{
options = { options = {
path = mkOption { path = mkOption {
type = types.str; type = types.str;
@ -216,9 +227,12 @@ let
''; '';
}; };
}; };
}); }
);
mailAccountOpts = { name, config, ... }: { mailAccountOpts =
{ name, config, ... }:
{
options = { options = {
name = mkOption { name = mkOption {
type = types.str; type = types.str;
@ -269,8 +283,12 @@ let
aliases = mkOption { aliases = mkOption {
description = "Alternative identities of this account."; description = "Alternative identities of this account.";
default = [ ]; default = [ ];
example = [ "webmaster@example.org" "admin@example.org" ]; example = [
type = types.listOf (types.oneOf [ "webmaster@example.org"
"admin@example.org"
];
type = types.listOf (
types.oneOf [
(types.strMatching ".*@.*") (types.strMatching ".*@.*")
(types.submodule { (types.submodule {
options = { options = {
@ -286,7 +304,8 @@ let
}; };
}; };
}) })
]); ]
);
}; };
realName = mkOption { realName = mkOption {
@ -399,7 +418,9 @@ let
maildir = mkOption { maildir = mkOption {
type = types.nullOr maildirModule; type = types.nullOr maildirModule;
defaultText = { path = "\${name}"; }; defaultText = {
path = "\${name}";
};
description = '' description = ''
Maildir configuration for this account. Maildir configuration for this account.
''; '';
@ -508,7 +529,8 @@ let
]; ];
}; };
in { in
{
options.accounts.email = { options.accounts.email = {
certificatesFile = mkOption { certificatesFile = mkOption {
type = types.nullOr types.path; type = types.nullOr types.path;
@ -524,8 +546,7 @@ in {
type = types.str; type = types.str;
default = "${config.home.homeDirectory}/Maildir"; default = "${config.home.homeDirectory}/Maildir";
defaultText = "Maildir"; defaultText = "Maildir";
apply = p: apply = p: if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
description = '' description = ''
The base directory for account maildir directories. May be a The base directory for account maildir directories. May be a
relative path (e.g. the user setting this value as "MyMaildir"), relative path (e.g. the user setting this value as "MyMaildir"),
@ -543,16 +564,18 @@ in {
config = mkIf (cfg.accounts != { }) { config = mkIf (cfg.accounts != { }) {
assertions = [ assertions = [
(let (
primaries = lib.catAttrs "name" let
(lib.filter (a: a.primary) (lib.attrValues cfg.accounts)); primaries = lib.catAttrs "name" (lib.filter (a: a.primary) (lib.attrValues cfg.accounts));
in { in
{
assertion = lib.length primaries == 1; assertion = lib.length primaries == 1;
message = "Must have exactly one primary mail account but found " message =
"Must have exactly one primary mail account but found "
+ toString (lib.length primaries) + toString (lib.length primaries)
+ lib.optionalString (lib.length primaries > 1) + lib.optionalString (lib.length primaries > 1) (", namely " + lib.concatStringsSep ", " primaries);
(", namely " + lib.concatStringsSep ", " primaries); }
}) )
]; ];
}; };
} }

View file

@ -1,9 +1,27 @@
{ config, options, lib, pkgs, ... }: {
config,
options,
lib,
pkgs,
...
}:
let let
inherit (lib) inherit (lib)
mkEnableOption mkOption mkIf mkMerge mkDefault mkAliasOptionModule types mkEnableOption
literalExpression escapeShellArg hm getAttrFromPath any optional; mkOption
mkIf
mkMerge
mkDefault
mkAliasOptionModule
types
literalExpression
escapeShellArg
hm
getAttrFromPath
any
optional
;
cfg = config.home.pointerCursor; cfg = config.home.pointerCursor;
opts = options.home.pointerCursor; opts = options.home.pointerCursor;
@ -51,9 +69,11 @@ let
}; };
dotIcons = { dotIcons = {
enable = mkEnableOption '' enable =
mkEnableOption ''
`.icons` config generation for {option}`home.pointerCursor` `.icons` config generation for {option}`home.pointerCursor`
'' // { ''
// {
default = true; default = true;
}; };
}; };
@ -70,15 +90,12 @@ let
}; };
sway = { sway = {
enable = mkEnableOption enable = mkEnableOption "sway config generation for {option}`home.pointerCursor`";
"sway config generation for {option}`home.pointerCursor`";
}; };
}; };
}; };
cursorPath = "${cfg.package}/share/icons/${escapeShellArg cfg.name}/cursors/${ cursorPath = "${cfg.package}/share/icons/${escapeShellArg cfg.name}/cursors/${escapeShellArg cfg.x11.defaultCursor}";
escapeShellArg cfg.x11.defaultCursor
}";
defaultIndexThemePackage = pkgs.writeTextFile { defaultIndexThemePackage = pkgs.writeTextFile {
name = "index.theme"; name = "index.theme";
@ -94,31 +111,44 @@ let
''; '';
}; };
in { in
{
meta.maintainers = [ lib.maintainers.league ]; meta.maintainers = [ lib.maintainers.league ];
imports = [ imports = [
(mkAliasOptionModule [ "xsession" "pointerCursor" "package" ] [ (mkAliasOptionModule
[ "xsession" "pointerCursor" "package" ]
[
"home" "home"
"pointerCursor" "pointerCursor"
"package" "package"
]) ]
(mkAliasOptionModule [ "xsession" "pointerCursor" "name" ] [ )
(mkAliasOptionModule
[ "xsession" "pointerCursor" "name" ]
[
"home" "home"
"pointerCursor" "pointerCursor"
"name" "name"
]) ]
(mkAliasOptionModule [ "xsession" "pointerCursor" "size" ] [ )
(mkAliasOptionModule
[ "xsession" "pointerCursor" "size" ]
[
"home" "home"
"pointerCursor" "pointerCursor"
"size" "size"
]) ]
(mkAliasOptionModule [ "xsession" "pointerCursor" "defaultCursor" ] [ )
(mkAliasOptionModule
[ "xsession" "pointerCursor" "defaultCursor" ]
[
"home" "home"
"pointerCursor" "pointerCursor"
"x11" "x11"
"defaultCursor" "defaultCursor"
]) ]
)
]; ];
options = { options = {
@ -145,21 +175,25 @@ in {
}; };
}; };
config = let config =
let
# Check if enable option was explicitly defined by the user # Check if enable option was explicitly defined by the user
enableDefined = any (x: x ? enable) opts.definitions; enableDefined = any (x: x ? enable) opts.definitions;
# Determine if cursor configuration should be enabled # Determine if cursor configuration should be enabled
enable = if enableDefined then cfg.enable else cfg != null; enable = if enableDefined then cfg.enable else cfg != null;
in mkMerge [ in
mkMerge [
(mkIf enable (mkMerge [ (mkIf enable (mkMerge [
{ {
assertions = [ assertions = [
(hm.assertions.assertPlatform "home.pointerCursor" pkgs (hm.assertions.assertPlatform "home.pointerCursor" pkgs lib.platforms.linux)
lib.platforms.linux)
]; ];
home.packages = [ cfg.package defaultIndexThemePackage ]; home.packages = [
cfg.package
defaultIndexThemePackage
];
home.sessionVariables = { home.sessionVariables = {
XCURSOR_SIZE = mkDefault cfg.size; XCURSOR_SIZE = mkDefault cfg.size;
@ -170,14 +204,12 @@ in {
# that are unable to find cursors otherwise. See: # that are unable to find cursors otherwise. See:
# https://github.com/nix-community/home-manager/issues/2812 # https://github.com/nix-community/home-manager/issues/2812
# https://wiki.archlinux.org/title/Cursor_themes#Environment_variable # https://wiki.archlinux.org/title/Cursor_themes#Environment_variable
home.sessionSearchVariables.XCURSOR_PATH = home.sessionSearchVariables.XCURSOR_PATH = [ "${config.home.profileDirectory}/share/icons" ];
[ "${config.home.profileDirectory}/share/icons" ];
# Add cursor icon link to $XDG_DATA_HOME/icons as well for redundancy. # Add cursor icon link to $XDG_DATA_HOME/icons as well for redundancy.
xdg.dataFile."icons/default/index.theme".source = xdg.dataFile."icons/default/index.theme".source =
"${defaultIndexThemePackage}/share/icons/default/index.theme"; "${defaultIndexThemePackage}/share/icons/default/index.theme";
xdg.dataFile."icons/${cfg.name}".source = xdg.dataFile."icons/${cfg.name}".source = "${cfg.package}/share/icons/${cfg.name}";
"${cfg.package}/share/icons/${cfg.name}";
} }
(mkIf cfg.dotIcons.enable { (mkIf cfg.dotIcons.enable {
@ -186,15 +218,12 @@ in {
# https://specifications.freedesktop.org/icon-theme-spec/latest/ar01s03.html # https://specifications.freedesktop.org/icon-theme-spec/latest/ar01s03.html
home.file.".icons/default/index.theme".source = home.file.".icons/default/index.theme".source =
"${defaultIndexThemePackage}/share/icons/default/index.theme"; "${defaultIndexThemePackage}/share/icons/default/index.theme";
home.file.".icons/${cfg.name}".source = home.file.".icons/${cfg.name}".source = "${cfg.package}/share/icons/${cfg.name}";
"${cfg.package}/share/icons/${cfg.name}";
}) })
(mkIf cfg.x11.enable { (mkIf cfg.x11.enable {
xsession.profileExtra = '' xsession.profileExtra = ''
${pkgs.xorg.xsetroot}/bin/xsetroot -xcf ${cursorPath} ${ ${pkgs.xorg.xsetroot}/bin/xsetroot -xcf ${cursorPath} ${toString cfg.size}
toString cfg.size
}
''; '';
xresources.properties = { xresources.properties = {
@ -210,10 +239,7 @@ in {
(mkIf cfg.hyprcursor.enable { (mkIf cfg.hyprcursor.enable {
home.sessionVariables = { home.sessionVariables = {
HYPRCURSOR_THEME = cfg.name; HYPRCURSOR_THEME = cfg.name;
HYPRCURSOR_SIZE = if cfg.hyprcursor.size != null then HYPRCURSOR_SIZE = if cfg.hyprcursor.size != null then cfg.hyprcursor.size else cfg.size;
cfg.hyprcursor.size
else
cfg.size;
}; };
}) })
@ -222,8 +248,7 @@ in {
config = { config = {
seat = { seat = {
"*" = { "*" = {
xcursor_theme = xcursor_theme = "${cfg.name} ${toString config.gtk.cursorTheme.size}";
"${cfg.name} ${toString config.gtk.cursorTheme.size}";
}; };
}; };
}; };
@ -232,15 +257,34 @@ in {
])) ]))
{ {
warnings = (optional (any (x: warnings =
getAttrFromPath (optional
([ "xsession" "pointerCursor" ] ++ [ x ] ++ [ "isDefined" ]) (any
options) [ "package" "name" "size" "defaultCursor" ]) '' (
x:
getAttrFromPath (
[
"xsession"
"pointerCursor"
]
++ [ x ]
++ [ "isDefined" ]
) options
)
[
"package"
"name"
"size"
"defaultCursor"
]
)
''
The option `xsession.pointerCursor` has been merged into `home.pointerCursor` and will be removed The option `xsession.pointerCursor` has been merged into `home.pointerCursor` and will be removed
in the future. Please change to set `home.pointerCursor` directly and enable `home.pointerCursor.x11.enable` in the future. Please change to set `home.pointerCursor` directly and enable `home.pointerCursor.x11.enable`
to generate x11 specific cursor configurations. You can refer to the documentation for more details. to generate x11 specific cursor configurations. You can refer to the documentation for more details.
'') ++ (optional (opts.highestPrio != (lib.mkOptionDefault { }).priority ''
&& cfg == null) '' )
++ (optional (opts.highestPrio != (lib.mkOptionDefault { }).priority && cfg == null) ''
Setting home.pointerCursor to null is deprecated. Setting home.pointerCursor to null is deprecated.
Please update your configuration to explicitly set: Please update your configuration to explicitly set:

View file

@ -15,7 +15,12 @@
# below for changes: # below for changes:
# https://github.com/NixOS/nixpkgs/blob/nixpkgs-unstable/pkgs/development/libraries/glibc/nix-locale-archive.patch # https://github.com/NixOS/nixpkgs/blob/nixpkgs-unstable/pkgs/development/libraries/glibc/nix-locale-archive.patch
{ lib, pkgs, config, ... }: {
lib,
pkgs,
config,
...
}:
let let
inherit (config.i18n) glibcLocales; inherit (config.i18n) glibcLocales;
@ -25,14 +30,20 @@ let
archivePath = "${glibcLocales}/lib/locale/locale-archive"; archivePath = "${glibcLocales}/lib/locale/locale-archive";
# lookup the version of glibcLocales and set the appropriate environment vars # lookup the version of glibcLocales and set the appropriate environment vars
localeVars = if lib.versionAtLeast version "2.27" then { localeVars =
if lib.versionAtLeast version "2.27" then
{
LOCALE_ARCHIVE_2_27 = archivePath; LOCALE_ARCHIVE_2_27 = archivePath;
} else if lib.versionAtLeast version "2.11" then { }
else if lib.versionAtLeast version "2.11" then
{
LOCALE_ARCHIVE_2_11 = archivePath; LOCALE_ARCHIVE_2_11 = archivePath;
} else }
else
{ }; { };
in { in
{
meta.maintainers = with lib.maintainers; [ midchildan ]; meta.maintainers = with lib.maintainers; [ midchildan ];
options = { options = {

View file

@ -1,18 +1,24 @@
{ configuration, pkgs, lib ? pkgs.lib {
configuration,
pkgs,
lib ? pkgs.lib,
# Whether to check that each option has a matching declaration. # Whether to check that each option has a matching declaration.
, check ? true check ? true,
# Extra arguments passed to specialArgs. # Extra arguments passed to specialArgs.
, extraSpecialArgs ? { } }: extraSpecialArgs ? { },
}:
let let
collectFailed = cfg: collectFailed = cfg: map (x: x.message) (lib.filter (x: !x.assertion) cfg.assertions);
map (x: x.message) (lib.filter (x: !x.assertion) cfg.assertions);
showWarnings = res: showWarnings =
let f = w: x: builtins.trace "warning: ${w}" x; res:
in lib.fold f res res.config.warnings; let
f = w: x: builtins.trace "warning: ${w}" x;
in
lib.fold f res res.config.warnings;
extendedLib = import ./lib/stdlib-extended.nix lib; extendedLib = import ./lib/stdlib-extended.nix lib;
@ -24,24 +30,33 @@ let
rawModule = extendedLib.evalModules { rawModule = extendedLib.evalModules {
modules = [ configuration ] ++ hmModules; modules = [ configuration ] ++ hmModules;
class = "homeManager"; class = "homeManager";
specialArgs = { modulesPath = builtins.toString ./.; } // extraSpecialArgs; specialArgs = {
modulesPath = builtins.toString ./.;
} // extraSpecialArgs;
}; };
moduleChecks = raw: moduleChecks =
showWarnings (let raw:
showWarnings (
let
failed = collectFailed raw.config; failed = collectFailed raw.config;
failedStr = lib.concatStringsSep "\n" (map (x: "- ${x}") failed); failedStr = lib.concatStringsSep "\n" (map (x: "- ${x}") failed);
in if failed == [ ] then in
if failed == [ ] then
raw raw
else else
throw '' throw ''
Failed assertions: Failed assertions:
${failedStr}''); ${failedStr}''
);
withExtraAttrs = rawModule: withExtraAttrs =
let module = moduleChecks rawModule; rawModule:
in { let
module = moduleChecks rawModule;
in
{
inherit (module) options config; inherit (module) options config;
activationPackage = module.config.home.activationPackage; activationPackage = module.config.home.activationPackage;
@ -50,11 +65,13 @@ let
activation-script = module.config.home.activationPackage; activation-script = module.config.home.activationPackage;
newsDisplay = rawModule.config.news.display; newsDisplay = rawModule.config.news.display;
newsEntries = lib.sort (a: b: a.time > b.time) newsEntries = lib.sort (a: b: a.time > b.time) (
(lib.filter (a: a.condition) rawModule.config.news.entries); lib.filter (a: a.condition) rawModule.config.news.entries
);
inherit (module._module.args) pkgs; inherit (module._module.args) pkgs;
extendModules = args: withExtraAttrs (rawModule.extendModules args); extendModules = args: withExtraAttrs (rawModule.extendModules args);
}; };
in withExtraAttrs rawModule in
withExtraAttrs rawModule

View file

@ -1,4 +1,9 @@
{ pkgs, config, lib, ... }: {
pkgs,
config,
lib,
...
}:
let let
@ -6,18 +11,24 @@ let
homeDirectory = config.home.homeDirectory; homeDirectory = config.home.homeDirectory;
fileType = (import lib/file-type.nix { fileType =
(import lib/file-type.nix {
inherit homeDirectory lib pkgs; inherit homeDirectory lib pkgs;
}).fileType; }).fileType;
sourceStorePath = file: sourceStorePath =
file:
let let
sourcePath = toString file.source; sourcePath = toString file.source;
sourceName = config.lib.strings.storeFileName (baseNameOf sourcePath); sourceName = config.lib.strings.storeFileName (baseNameOf sourcePath);
in in
if builtins.hasContext sourcePath if builtins.hasContext sourcePath then
then file.source file.source
else builtins.path { path = file.source; name = sourceName; }; else
builtins.path {
path = file.source;
name = sourceName;
};
in in
@ -37,15 +48,17 @@ in
}; };
config = { config = {
assertions = [( assertions = [
(
let let
dups = dups = lib.attrNames (
lib.attrNames lib.filterAttrs (n: v: v > 1) (
(lib.filterAttrs (n: v: v > 1) lib.foldAttrs (acc: v: acc + v) 0 (lib.mapAttrsToList (n: v: { ${v.target} = 1; }) cfg)
(lib.foldAttrs (acc: v: acc + v) 0 )
(lib.mapAttrsToList (n: v: { ${v.target} = 1; }) cfg))); );
dupsStr = lib.concatStringsSep ", " dups; dupsStr = lib.concatStringsSep ", " dups;
in { in
{
assertion = dups == [ ]; assertion = dups == [ ];
message = '' message = ''
Conflicting managed target files: ${dupsStr} Conflicting managed target files: ${dupsStr}
@ -56,7 +69,8 @@ in
conflict1 = { source = ./foo.nix; target = "baz"; }; conflict1 = { source = ./foo.nix; target = "baz"; };
conflict2 = { source = ./bar.nix; target = "baz"; }; conflict2 = { source = ./bar.nix; target = "baz"; };
}''; }'';
}) }
)
]; ];
# Using this function it is possible to make `home.file` create a # Using this function it is possible to make `home.file` create a
@ -67,7 +81,8 @@ in
# #
# would upon activation create a symlink `~/foo` that points to the # would upon activation create a symlink `~/foo` that points to the
# absolute path of the `bar` file relative the configuration file. # absolute path of the `bar` file relative the configuration file.
lib.file.mkOutOfStoreSymlink = path: lib.file.mkOutOfStoreSymlink =
path:
let let
pathStr = toString path; pathStr = toString path;
name = lib.hm.strings.storeFileName (baseNameOf pathStr); name = lib.hm.strings.storeFileName (baseNameOf pathStr);
@ -80,10 +95,9 @@ in
let let
# Paths that should be forcibly overwritten by Home Manager. # Paths that should be forcibly overwritten by Home Manager.
# Caveat emptor! # Caveat emptor!
forcedPaths = forcedPaths = lib.concatMapStringsSep " " (p: ''"$HOME"/${lib.escapeShellArg p}'') (
lib.concatMapStringsSep " " (p: ''"$HOME"/${lib.escapeShellArg p}'') lib.mapAttrsToList (n: v: v.target) (lib.filterAttrs (n: v: v.force) cfg)
(lib.mapAttrsToList (n: v: v.target) );
(lib.filterAttrs (n: v: v.force) cfg));
storeDir = lib.escapeShellArg builtins.storeDir; storeDir = lib.escapeShellArg builtins.storeDir;
@ -225,7 +239,8 @@ in
home.activation.checkFilesChanged = lib.hm.dag.entryBefore [ "linkGeneration" ] ( home.activation.checkFilesChanged = lib.hm.dag.entryBefore [ "linkGeneration" ] (
let let
homeDirArg = lib.escapeShellArg homeDirectory; homeDirArg = lib.escapeShellArg homeDirectory;
in '' in
''
function _cmp() { function _cmp() {
if [[ -d $1 && -d $2 ]]; then if [[ -d $1 && -d $2 ]]; then
diff -rq "$1" "$2" &> /dev/null diff -rq "$1" "$2" &> /dev/null
@ -234,15 +249,19 @@ in
fi fi
} }
declare -A changedFiles declare -A changedFiles
'' + lib.concatMapStrings (v: ''
+ lib.concatMapStrings (
v:
let let
sourceArg = lib.escapeShellArg (sourceStorePath v); sourceArg = lib.escapeShellArg (sourceStorePath v);
targetArg = lib.escapeShellArg v.target; targetArg = lib.escapeShellArg v.target;
in '' in
''
_cmp ${sourceArg} ${homeDirArg}/${targetArg} \ _cmp ${sourceArg} ${homeDirArg}/${targetArg} \
&& changedFiles[${targetArg}]=0 \ && changedFiles[${targetArg}]=0 \
|| changedFiles[${targetArg}]=1 || changedFiles[${targetArg}]=1
'') (lib.filter (v: v.onChange != "") (lib.attrValues cfg)) ''
) (lib.filter (v: v.onChange != "") (lib.attrValues cfg))
+ '' + ''
unset -f _cmp unset -f _cmp
'' ''
@ -263,12 +282,13 @@ in
# Symlink directories and files that have the right execute bit. # Symlink directories and files that have the right execute bit.
# Copy files that need their execute bit changed. # Copy files that need their execute bit changed.
home-files = pkgs.runCommandLocal home-files =
"home-manager-files" pkgs.runCommandLocal "home-manager-files"
{ {
nativeBuildInputs = [ pkgs.xorg.lndir ]; nativeBuildInputs = [ pkgs.xorg.lndir ];
} }
('' (
''
mkdir -p $out mkdir -p $out
# Needed in case /nix is a symbolic link. # Needed in case /nix is a symbolic link.
@ -330,18 +350,19 @@ in
fi fi
fi fi
} }
'' + lib.concatStrings ( ''
+ lib.concatStrings (
lib.mapAttrsToList (n: v: '' lib.mapAttrsToList (n: v: ''
insertFile ${ insertFile ${
lib.escapeShellArgs [ lib.escapeShellArgs [
(sourceStorePath v) (sourceStorePath v)
v.target v.target
(if v.executable == null (if v.executable == null then "inherit" else toString v.executable)
then "inherit"
else toString v.executable)
(toString v.recursive) (toString v.recursive)
]} ]
}
'') cfg '') cfg
)); )
);
}; };
} }

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) literalExpression mkOption types; inherit (lib) literalExpression mkOption types;
@ -112,10 +117,7 @@ let
options = { options = {
layout = mkOption { layout = mkOption {
type = with types; nullOr str; type = with types; nullOr str;
default = default = if lib.versionAtLeast config.home.stateVersion "19.09" then null else "us";
if lib.versionAtLeast config.home.stateVersion "19.09"
then null
else "us";
defaultText = literalExpression "null"; defaultText = literalExpression "null";
description = '' description = ''
Keyboard layout. If `null`, then the system Keyboard layout. If `null`, then the system
@ -138,7 +140,10 @@ let
options = mkOption { options = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ ]; default = [ ];
example = ["grp:caps_toggle" "grp_led:scroll"]; example = [
"grp:caps_toggle"
"grp_led:scroll"
];
description = '' description = ''
X keyboard options; layout switching goes here. X keyboard options; layout switching goes here.
''; '';
@ -146,10 +151,7 @@ let
variant = mkOption { variant = mkOption {
type = with types; nullOr str; type = with types; nullOr str;
default = default = if lib.versionAtLeast config.home.stateVersion "19.09" then null else "";
if lib.versionAtLeast config.home.stateVersion "19.09"
then null
else "";
defaultText = literalExpression "null"; defaultText = literalExpression "null";
example = "colemak"; example = "colemak";
description = '' description = ''
@ -255,8 +257,18 @@ in
home.sessionVariables = mkOption { home.sessionVariables = mkOption {
default = { }; default = { };
type = with types; lazyAttrsOf (oneOf [ str path int float ]); type =
example = { EDITOR = "emacs"; GS_OPTIONS = "-sPAPERSIZE=a4"; }; with types;
lazyAttrsOf (oneOf [
str
path
int
float
]);
example = {
EDITOR = "emacs";
GS_OPTIONS = "-sPAPERSIZE=a4";
};
description = '' description = ''
Environment variables to always set at login. Environment variables to always set at login.
@ -359,7 +371,11 @@ in
home.extraOutputsToInstall = mkOption { home.extraOutputsToInstall = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ ]; default = [ ];
example = [ "doc" "info" "devdoc" ]; example = [
"doc"
"info"
"devdoc"
];
description = '' description = ''
List of additional package outputs of the packages List of additional package outputs of the packages
{var}`home.packages` that should be installed into {var}`home.packages` that should be installed into
@ -518,9 +534,7 @@ in
let let
hmRelease = config.home.version.release; hmRelease = config.home.version.release;
nixpkgsRelease = lib.trivial.release; nixpkgsRelease = lib.trivial.release;
releaseMismatch = releaseMismatch = config.home.enableNixpkgsReleaseCheck && hmRelease != nixpkgsRelease;
config.home.enableNixpkgsReleaseCheck
&& hmRelease != nixpkgsRelease;
in in
lib.optional releaseMismatch '' lib.optional releaseMismatch ''
You are using You are using
@ -539,20 +553,20 @@ in
to your configuration. to your configuration.
''; '';
home.username = home.username = lib.mkIf (lib.versionOlder config.home.stateVersion "20.09") (
lib.mkIf (lib.versionOlder config.home.stateVersion "20.09") lib.mkDefault (builtins.getEnv "USER")
(lib.mkDefault (builtins.getEnv "USER")); );
home.homeDirectory = home.homeDirectory = lib.mkIf (lib.versionOlder config.home.stateVersion "20.09") (
lib.mkIf (lib.versionOlder config.home.stateVersion "20.09") lib.mkDefault (builtins.getEnv "HOME")
(lib.mkDefault (builtins.getEnv "HOME")); );
home.profileDirectory = home.profileDirectory =
if config.submoduleSupport.enable if config.submoduleSupport.enable && config.submoduleSupport.externalPackageInstall then
&& config.submoduleSupport.externalPackageInstall "/etc/profiles/per-user/${cfg.username}"
then "/etc/profiles/per-user/${cfg.username}" else if config.nix.enable && (config.nix.settings.use-xdg-base-directories or false) then
else if config.nix.enable && (config.nix.settings.use-xdg-base-directories or false) "${config.xdg.stateHome}/nix/profile"
then "${config.xdg.stateHome}/nix/profile" else
else cfg.homeDirectory + "/.nix-profile"; cfg.homeDirectory + "/.nix-profile";
programs.bash.shellAliases = cfg.shellAliases; programs.bash.shellAliases = cfg.shellAliases;
programs.zsh.shellAliases = cfg.shellAliases; programs.zsh.shellAliases = cfg.shellAliases;
@ -564,50 +578,40 @@ in
maybeSet = n: v: lib.optionalAttrs (v != null) { ${n} = v; }; maybeSet = n: v: lib.optionalAttrs (v != null) { ${n} = v; };
in in
(maybeSet "LANG" cfg.language.base) (maybeSet "LANG" cfg.language.base)
// // (maybeSet "LC_CTYPE" cfg.language.ctype)
(maybeSet "LC_CTYPE" cfg.language.ctype) // (maybeSet "LC_NUMERIC" cfg.language.numeric)
// // (maybeSet "LC_TIME" cfg.language.time)
(maybeSet "LC_NUMERIC" cfg.language.numeric) // (maybeSet "LC_COLLATE" cfg.language.collate)
// // (maybeSet "LC_MONETARY" cfg.language.monetary)
(maybeSet "LC_TIME" cfg.language.time) // (maybeSet "LC_MESSAGES" cfg.language.messages)
// // (maybeSet "LC_PAPER" cfg.language.paper)
(maybeSet "LC_COLLATE" cfg.language.collate) // (maybeSet "LC_NAME" cfg.language.name)
// // (maybeSet "LC_ADDRESS" cfg.language.address)
(maybeSet "LC_MONETARY" cfg.language.monetary) // (maybeSet "LC_TELEPHONE" cfg.language.telephone)
// // (maybeSet "LC_MEASUREMENT" cfg.language.measurement);
(maybeSet "LC_MESSAGES" cfg.language.messages)
//
(maybeSet "LC_PAPER" cfg.language.paper)
//
(maybeSet "LC_NAME" cfg.language.name)
//
(maybeSet "LC_ADDRESS" cfg.language.address)
//
(maybeSet "LC_TELEPHONE" cfg.language.telephone)
//
(maybeSet "LC_MEASUREMENT" cfg.language.measurement);
# Provide a file holding all session variables. # Provide a file holding all session variables.
home.sessionVariablesPackage = pkgs.writeTextFile { home.sessionVariablesPackage = pkgs.writeTextFile {
name = "hm-session-vars.sh"; name = "hm-session-vars.sh";
destination = "/etc/profile.d/hm-session-vars.sh"; destination = "/etc/profile.d/hm-session-vars.sh";
text = '' text =
''
# Only source this once. # Only source this once.
if [ -n "$__HM_SESS_VARS_SOURCED" ]; then return; fi if [ -n "$__HM_SESS_VARS_SOURCED" ]; then return; fi
export __HM_SESS_VARS_SOURCED=1 export __HM_SESS_VARS_SOURCED=1
${config.lib.shell.exportAll cfg.sessionVariables} ${config.lib.shell.exportAll cfg.sessionVariables}
'' + lib.concatStringsSep "\n" ''
(lib.mapAttrsToList + lib.concatStringsSep "\n" (
(env: values: config.lib.shell.export lib.mapAttrsToList (
env env: values: config.lib.shell.export env (config.lib.shell.prependToVar ":" env values)
(config.lib.shell.prependToVar ":" env values)) ) cfg.sessionSearchVariables
cfg.sessionSearchVariables) + "\n" )
+ "\n"
+ cfg.sessionVariablesExtra; + cfg.sessionVariablesExtra;
}; };
home.sessionSearchVariables.PATH = home.sessionSearchVariables.PATH = lib.mkIf (cfg.sessionPath != [ ]) cfg.sessionPath;
lib.mkIf (cfg.sessionPath != [ ]) cfg.sessionPath;
home.packages = [ config.home.sessionVariablesPackage ]; home.packages = [ config.home.sessionVariablesPackage ];
@ -639,8 +643,7 @@ in
# to a submodule managed one we attempt to uninstall the # to a submodule managed one we attempt to uninstall the
# `home-manager-path` package if it is installed. # `home-manager-path` package if it is installed.
home.activation.installPackages = lib.hm.dag.entryAfter [ "writeBoundary" ] ( home.activation.installPackages = lib.hm.dag.entryAfter [ "writeBoundary" ] (
if config.submoduleSupport.externalPackageInstall if config.submoduleSupport.externalPackageInstall then
then
'' ''
nixProfileRemove home-manager-path nixProfileRemove home-manager-path
'' ''
@ -681,9 +684,12 @@ in
# in the `hm-modules` text domain. # in the `hm-modules` text domain.
lib.bash.initHomeManagerLib = lib.bash.initHomeManagerLib =
let let
domainDir = pkgs.runCommand "hm-modules-messages" { domainDir =
pkgs.runCommand "hm-modules-messages"
{
nativeBuildInputs = [ pkgs.buildPackages.gettext ]; nativeBuildInputs = [ pkgs.buildPackages.gettext ];
} '' }
''
for path in ${./po}/*.po; do for path in ${./po}/*.po; do
lang="''${path##*/}" lang="''${path##*/}"
lang="''${lang%%.*}" lang="''${lang%%.*}"
@ -709,13 +715,14 @@ in
if sortedCommands ? result then if sortedCommands ? result then
lib.concatStringsSep "\n" (map mkCmd sortedCommands.result) lib.concatStringsSep "\n" (map mkCmd sortedCommands.result)
else else
abort ("Dependency cycle in activation script: " abort ("Dependency cycle in activation script: " + builtins.toJSON sortedCommands);
+ builtins.toJSON sortedCommands);
# Programs that always should be available on the activation # Programs that always should be available on the activation
# script's PATH. # script's PATH.
activationBinPaths = lib.makeBinPath ( activationBinPaths =
with pkgs; [ lib.makeBinPath (
with pkgs;
[
bash bash
coreutils coreutils
diffutils # For `cmp` and `diff`. diffutils # For `cmp` and `diff`.
@ -770,8 +777,7 @@ in
''} ''}
''; '';
in in
pkgs.runCommand pkgs.runCommand "home-manager-generation"
"home-manager-generation"
{ {
preferLocalBuild = true; preferLocalBuild = true;
} }

View file

@ -1,33 +1,65 @@
{ config, pkgs, lib, ... }: {
config,
pkgs,
lib,
...
}:
let let
cfg = config.i18n.inputMethod; cfg = config.i18n.inputMethod;
gtk2Cache = pkgs.runCommandLocal "gtk2-immodule.cache" { gtk2Cache =
buildInputs = [ pkgs.gtk2 cfg.package ]; pkgs.runCommandLocal "gtk2-immodule.cache"
} '' {
buildInputs = [
pkgs.gtk2
cfg.package
];
}
''
mkdir -p $out/etc/gtk-2.0/ mkdir -p $out/etc/gtk-2.0/
GTK_PATH=${cfg.package}/lib/gtk-2.0/ \ GTK_PATH=${cfg.package}/lib/gtk-2.0/ \
gtk-query-immodules-2.0 > $out/etc/gtk-2.0/immodules.cache gtk-query-immodules-2.0 > $out/etc/gtk-2.0/immodules.cache
''; '';
gtk3Cache = pkgs.runCommandLocal "gtk3-immodule.cache" { gtk3Cache =
buildInputs = [ pkgs.gtk3 cfg.package ]; pkgs.runCommandLocal "gtk3-immodule.cache"
} '' {
buildInputs = [
pkgs.gtk3
cfg.package
];
}
''
mkdir -p $out/etc/gtk-3.0/ mkdir -p $out/etc/gtk-3.0/
GTK_PATH=${cfg.package}/lib/gtk-3.0/ \ GTK_PATH=${cfg.package}/lib/gtk-3.0/ \
gtk-query-immodules-3.0 > $out/etc/gtk-3.0/immodules.cache gtk-query-immodules-3.0 > $out/etc/gtk-3.0/immodules.cache
''; '';
in { in
imports = [ ./fcitx5.nix ./hime.nix ./kime.nix ./nabi.nix ./uim.nix ]; {
imports = [
./fcitx5.nix
./hime.nix
./kime.nix
./nabi.nix
./uim.nix
];
options.i18n = { options.i18n = {
inputMethod = { inputMethod = {
enabled = lib.mkOption { enabled = lib.mkOption {
type = lib.types.nullOr type = lib.types.nullOr (
(lib.types.enum [ "fcitx" "fcitx5" "nabi" "uim" "hime" "kime" ]); lib.types.enum [
"fcitx"
"fcitx5"
"nabi"
"uim"
"hime"
"kime"
]
);
default = null; default = null;
example = "fcitx5"; example = "fcitx5";
description = '' description = ''
@ -73,15 +105,18 @@ in {
config = lib.mkIf (cfg.enabled != null) { config = lib.mkIf (cfg.enabled != null) {
assertions = [ assertions = [
(lib.hm.assertions.assertPlatform "i18n.inputMethod" pkgs (lib.hm.assertions.assertPlatform "i18n.inputMethod" pkgs lib.platforms.linux)
lib.platforms.linux)
{ {
assertion = cfg.enabled != "fcitx"; assertion = cfg.enabled != "fcitx";
message = "fcitx has been removed, please use fcitx5 instead"; message = "fcitx has been removed, please use fcitx5 instead";
} }
]; ];
home.packages = [ cfg.package gtk2Cache gtk3Cache ]; home.packages = [
cfg.package
gtk2Cache
gtk3Cache
];
}; };
meta.maintainers = [ lib.hm.maintainers.kranzes ]; meta.maintainers = [ lib.hm.maintainers.kranzes ];

View file

@ -1,9 +1,15 @@
{ config, pkgs, lib, ... }: {
config,
pkgs,
lib,
...
}:
let let
im = config.i18n.inputMethod; im = config.i18n.inputMethod;
cfg = im.fcitx5; cfg = im.fcitx5;
fcitx5Package = cfg.fcitx5-with-addons.override { inherit (cfg) addons; }; fcitx5Package = cfg.fcitx5-with-addons.override { inherit (cfg) addons; };
in { in
{
options = { options = {
i18n.inputMethod.fcitx5 = { i18n.inputMethod.fcitx5 = {
fcitx5-with-addons = lib.mkOption { fcitx5-with-addons = lib.mkOption {
@ -38,17 +44,18 @@ in {
i18n.inputMethod.package = fcitx5Package; i18n.inputMethod.package = fcitx5Package;
home = { home = {
sessionVariables = { sessionVariables =
{
GLFW_IM_MODULE = "ibus"; # IME support in kitty GLFW_IM_MODULE = "ibus"; # IME support in kitty
SDL_IM_MODULE = "fcitx"; SDL_IM_MODULE = "fcitx";
XMODIFIERS = "@im=fcitx"; XMODIFIERS = "@im=fcitx";
} // lib.optionalAttrs (!cfg.waylandFrontend) { }
// lib.optionalAttrs (!cfg.waylandFrontend) {
GTK_IM_MODULE = "fcitx"; GTK_IM_MODULE = "fcitx";
QT_IM_MODULE = "fcitx"; QT_IM_MODULE = "fcitx";
}; };
sessionSearchVariables.QT_PLUGIN_PATH = sessionSearchVariables.QT_PLUGIN_PATH = [ "${fcitx5Package}/${pkgs.qt6.qtbase.qtPluginPrefix}" ];
[ "${fcitx5Package}/${pkgs.qt6.qtbase.qtPluginPrefix}" ];
}; };
systemd.user.services.fcitx5-daemon = { systemd.user.services.fcitx5-daemon = {

View file

@ -1,4 +1,9 @@
{ config, pkgs, lib, ... }: {
config,
pkgs,
lib,
...
}:
{ {
config = lib.mkIf (config.i18n.inputMethod.enabled == "hime") { config = lib.mkIf (config.i18n.inputMethod.enabled == "hime") {

View file

@ -1,10 +1,22 @@
{ config, pkgs, lib, ... }: {
config,
pkgs,
lib,
...
}:
let let
inherit (lib) literalExpression mkIf mkOption mkRemovedOptionModule types; inherit (lib)
literalExpression
mkIf
mkOption
mkRemovedOptionModule
types
;
cfg = config.i18n.inputMethod.kime; cfg = config.i18n.inputMethod.kime;
in { in
{
imports = [ imports = [
(mkRemovedOptionModule [ "i18n" "inputMethod" "kime" "config" ] '' (mkRemovedOptionModule [ "i18n" "inputMethod" "kime" "config" ] ''
Please use 'i18n.inputMethod.kime.extraConfig' instead. Please use 'i18n.inputMethod.kime.extraConfig' instead.

View file

@ -1,4 +1,9 @@
{ config, pkgs, lib, ... }: {
config,
pkgs,
lib,
...
}:
{ {
config = lib.mkIf (config.i18n.inputMethod.enabled == "nabi") { config = lib.mkIf (config.i18n.inputMethod.enabled == "nabi") {

View file

@ -1,13 +1,25 @@
{ config, pkgs, lib, ... }: {
config,
pkgs,
lib,
...
}:
let cfg = config.i18n.inputMethod.uim; let
in { cfg = config.i18n.inputMethod.uim;
in
{
options = { options = {
i18n.inputMethod.uim = { i18n.inputMethod.uim = {
toolbar = lib.mkOption { toolbar = lib.mkOption {
type = type = lib.types.enum [
lib.types.enum [ "gtk" "gtk3" "gtk-systray" "gtk3-systray" "qt4" ]; "gtk"
"gtk3"
"gtk-systray"
"gtk3-systray"
"qt4"
];
default = "gtk"; default = "gtk";
example = "gtk-systray"; example = "gtk-systray";
description = '' description = ''
@ -32,11 +44,12 @@ in {
Description = "Uim input method editor"; Description = "Uim input method editor";
PartOf = [ "graphical-session.desktop" ]; PartOf = [ "graphical-session.desktop" ];
}; };
Service.ExecStart = toString Service.ExecStart = toString (
(pkgs.writeShellScript "start-uim-xim-and-uim-toolbar" '' pkgs.writeShellScript "start-uim-xim-and-uim-toolbar" ''
${pkgs.uim}/bin/uim-xim & ${pkgs.uim}/bin/uim-xim &
${pkgs.uim}/bin/uim-toolbar-${cfg.toolbar} ${pkgs.uim}/bin/uim-toolbar-${cfg.toolbar}
''); ''
);
Install.WantedBy = [ "graphical-session.target" ]; Install.WantedBy = [ "graphical-session.target" ];
}; };
}; };

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (pkgs.stdenv.hostPlatform) isDarwin; inherit (pkgs.stdenv.hostPlatform) isDarwin;
@ -8,7 +13,9 @@ let
labelPrefix = "org.nix-community.home."; labelPrefix = "org.nix-community.home.";
dstDir = "${config.home.homeDirectory}/Library/LaunchAgents"; dstDir = "${config.home.homeDirectory}/Library/LaunchAgents";
launchdConfig = { config, name, ... }: { launchdConfig =
{ config, name, ... }:
{
options = { options = {
enable = lib.mkEnableOption name; enable = lib.mkEnableOption name;
config = lib.mkOption { config = lib.mkOption {
@ -31,22 +38,23 @@ let
}; };
}; };
config = { config.Label = lib.mkDefault "${labelPrefix}${name}"; }; config = {
config.Label = lib.mkDefault "${labelPrefix}${name}";
};
}; };
toAgent = config: pkgs.writeText "${config.Label}.plist" (toPlist { } config); toAgent = config: pkgs.writeText "${config.Label}.plist" (toPlist { } config);
agentPlists = lib.mapAttrs' agentPlists = lib.mapAttrs' (n: v: lib.nameValuePair "${v.config.Label}.plist" (toAgent v.config)) (
(n: v: lib.nameValuePair "${v.config.Label}.plist" (toAgent v.config)) lib.filterAttrs (n: v: v.enable) cfg.agents
(lib.filterAttrs (n: v: v.enable) cfg.agents); );
agentsDrv = pkgs.runCommand "home-manager-agents" { } '' agentsDrv = pkgs.runCommand "home-manager-agents" { } ''
mkdir -p "$out" mkdir -p "$out"
declare -A plists declare -A plists
plists=(${ plists=(${
lib.concatStringsSep " " lib.concatStringsSep " " (lib.mapAttrsToList (name: value: "['${name}']='${value}'") agentPlists)
(lib.mapAttrsToList (name: value: "['${name}']='${value}'") agentPlists)
}) })
for dest in "''${!plists[@]}"; do for dest in "''${!plists[@]}"; do
@ -54,8 +62,12 @@ let
ln -s "$src" "$out/$dest" ln -s "$src" "$out/$dest"
done done
''; '';
in { in
meta.maintainers = with lib.maintainers; [ khaneliman midchildan ]; {
meta.maintainers = with lib.maintainers; [
khaneliman
midchildan
];
options.launchd = { options.launchd = {
enable = lib.mkOption { enable = lib.mkOption {
@ -77,12 +89,16 @@ in {
config = lib.mkMerge [ config = lib.mkMerge [
{ {
assertions = [{ assertions = [
{
assertion = (cfg.enable && agentPlists != { }) -> isDarwin; assertion = (cfg.enable && agentPlists != { }) -> isDarwin;
message = message =
let names = lib.concatStringsSep ", " (lib.attrNames agentPlists); let
in "Must use Darwin for modules that require Launchd: " + names; names = lib.concatStringsSep ", " (lib.attrNames agentPlists);
}]; in
"Must use Darwin for modules that require Launchd: " + names;
}
];
} }
(lib.mkIf isDarwin { (lib.mkIf isDarwin {

View file

@ -29,7 +29,8 @@ let
inherit (lib) types mkOption; # added by Home Manager inherit (lib) types mkOption; # added by Home Manager
launchdTypes = import ./types.nix { inherit config lib; }; launchdTypes = import ./types.nix { inherit config lib; };
in { in
{
freeformType = with types; attrsOf anything; # added by Home Manager freeformType = with types; attrsOf anything; # added by Home Manager
options = { options = {
@ -82,11 +83,14 @@ in {
inetdCompatibility = mkOption { inetdCompatibility = mkOption {
default = null; default = null;
example = { Wait = true; }; example = {
Wait = true;
};
description = '' description = ''
The presence of this key specifies that the daemon expects to be run as if it were launched from inetd. The presence of this key specifies that the daemon expects to be run as if it were launched from inetd.
''; '';
type = types.nullOr (types.submodule { type = types.nullOr (
types.submodule {
options = { options = {
Wait = mkOption { Wait = mkOption {
type = types.nullOr (types.either types.bool types.str); type = types.nullOr (types.either types.bool types.str);
@ -98,7 +102,8 @@ in {
''; '';
}; };
}; };
}); }
);
}; };
LimitLoadToHosts = mkOption { LimitLoadToHosts = mkOption {
@ -120,7 +125,12 @@ in {
}; };
LimitLoadToSessionType = mkOption { LimitLoadToSessionType = mkOption {
type = types.nullOr (types.oneOf [ types.str (types.listOf types.str) ]); type = types.nullOr (
types.oneOf [
types.str
(types.listOf types.str)
]
);
default = null; default = null;
description = '' description = ''
This configuration file only applies to sessions of the type specified. This key is used in concert This configuration file only applies to sessions of the type specified. This key is used in concert
@ -177,7 +187,9 @@ in {
}; };
KeepAlive = mkOption { KeepAlive = mkOption {
type = types.nullOr (types.either types.bool (types.submodule { type = types.nullOr (
types.either types.bool (
types.submodule {
options = { options = {
SuccessfulExit = mkOption { SuccessfulExit = mkOption {
@ -238,7 +250,9 @@ in {
}; };
}; };
})); }
)
);
default = null; default = null;
description = '' description = ''
This optional key is used to control whether your job is to be kept continuously running or to let This optional key is used to control whether your job is to be kept continuously running or to let
@ -371,10 +385,12 @@ in {
StartCalendarInterval = mkOption { StartCalendarInterval = mkOption {
default = null; default = null;
example = [{ example = [
{
Hour = 2; Hour = 2;
Minute = 30; Minute = 30;
}]; }
];
description = '' description = ''
This optional key causes the job to be started every calendar interval as specified. The semantics are 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 much like {manpage}`crontab(5)`: Missing attributes are considered to be wildcard. Unlike cron which skips
@ -442,7 +458,8 @@ in {
Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following
keys apply: keys apply:
''; '';
type = types.nullOr (types.submodule { type = types.nullOr (
types.submodule {
options = { options = {
Core = mkOption { Core = mkOption {
type = types.nullOr types.int; type = types.nullOr types.int;
@ -524,17 +541,21 @@ in {
''; '';
}; };
}; };
}); }
);
}; };
HardResourceLimits = mkOption { HardResourceLimits = mkOption {
default = null; default = null;
example = { NumberOfFiles = 4096; }; example = {
NumberOfFiles = 4096;
};
description = '' description = ''
Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following
keys apply: keys apply:
''; '';
type = types.nullOr (types.submodule { type = types.nullOr (
types.submodule {
options = { options = {
Core = mkOption { Core = mkOption {
type = types.nullOr types.int; type = types.nullOr types.int;
@ -616,7 +637,8 @@ in {
''; '';
}; };
}; };
}); }
);
}; };
Nice = mkOption { Nice = mkOption {
@ -628,8 +650,14 @@ in {
}; };
ProcessType = mkOption { ProcessType = mkOption {
type = types.nullOr type = types.nullOr (
(types.enum [ "Background" "Standard" "Adaptive" "Interactive" ]); types.enum [
"Background"
"Standard"
"Adaptive"
"Interactive"
]
);
default = null; default = null;
example = "Background"; example = "Background";
description = '' description = ''
@ -694,7 +722,11 @@ in {
MachServices = mkOption { MachServices = mkOption {
default = null; default = null;
example = { "org.nixos.service" = { ResetAtClose = true; }; }; example = {
"org.nixos.service" = {
ResetAtClose = true;
};
};
description = '' description = ''
This optional key is used to specify Mach services to be registered with the Mach bootstrap sub-system. 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 Each key in this dictionary should be the name of service to be advertised. The value of the key must
@ -703,8 +735,10 @@ in {
Finally, for the job itself, the values will be replaced with Mach ports at the time of check-in with Finally, for the job itself, the values will be replaced with Mach ports at the time of check-in with
launchd. launchd.
''; '';
type = types.nullOr (types.attrsOf (types.either types.bool type = types.nullOr (
(types.submodule { types.attrsOf (
types.either types.bool (
types.submodule {
options = { options = {
ResetAtClose = mkOption { ResetAtClose = mkOption {
type = types.nullOr types.bool; type = types.nullOr types.bool;
@ -728,7 +762,10 @@ in {
''; '';
}; };
}; };
}))); }
)
)
);
}; };
LaunchEvents = mkOption { LaunchEvents = mkOption {
@ -790,10 +827,18 @@ in {
The parameters below are used as inputs to call `getaddrinfo(3)`. The parameters below are used as inputs to call `getaddrinfo(3)`.
''; '';
type = types.nullOr (types.attrsOf (types.submodule { type = types.nullOr (
types.attrsOf (
types.submodule {
options = { options = {
SockType = mkOption { SockType = mkOption {
type = types.nullOr (types.enum [ "stream" "dgram" "seqpacket" ]); type = types.nullOr (
types.enum [
"stream"
"dgram"
"seqpacket"
]
);
default = null; default = null;
description = '' description = ''
This optional key tells launchctl what type of socket to create. The default is "stream" and This optional key tells launchctl what type of socket to create. The default is "stream" and
@ -827,7 +872,12 @@ in {
}; };
SockFamily = mkOption { SockFamily = mkOption {
type = types.nullOr (types.enum [ "IPv4" "IPv6" ]); type = types.nullOr (
types.enum [
"IPv4"
"IPv6"
]
);
default = null; default = null;
description = '' description = ''
This optional key can be used to specifically request that "IPv4" or "IPv6" socket(s) be created. This optional key can be used to specifically request that "IPv4" or "IPv6" socket(s) be created.
@ -872,8 +922,7 @@ in {
}; };
Bonjour = mkOption { Bonjour = mkOption {
type = type = types.nullOr (types.either types.bool (types.listOf types.str));
types.nullOr (types.either types.bool (types.listOf types.str));
default = null; default = null;
description = '' description = ''
This optional key can be used to request that the service be registered with the This optional key can be used to request that the service be registered with the
@ -892,7 +941,9 @@ in {
''; '';
}; };
}; };
})); }
)
);
}; };
}; };

View file

@ -5,12 +5,27 @@
{ lib, ... }: { lib, ... }:
let let
inherit (lib) imap1 types mkOption showOption mergeDefinitions; inherit (lib)
inherit (builtins) map filter length deepSeq throw toString concatLists; imap1
types
mkOption
showOption
mergeDefinitions
;
inherit (builtins)
map
filter
length
deepSeq
throw
toString
concatLists
;
inherit (lib.options) showDefs; inherit (lib.options) showDefs;
wildcardText = lib.literalMD "`*`"; wildcardText = lib.literalMD "`*`";
/* * /*
*
A type of list which does not allow duplicate elements. The base/inner 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 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. via argument `listType`, which must be the final type and not a function.
@ -25,49 +40,63 @@ let
The implementation of this function is similar to that of The implementation of this function is similar to that of
`types.nonEmptyListOf`. `types.nonEmptyListOf`.
*/ */
types'.uniqueList = listType: types'.uniqueList =
listType // { listType:
description = "unique ${ listType
types.optionDescriptionPhrase (class: class == "noun") listType // {
}"; description = "unique ${types.optionDescriptionPhrase (class: class == "noun") listType}";
substSubModules = m: types'.uniqueList (listType.substSubModules m); substSubModules = m: types'.uniqueList (listType.substSubModules m);
# This has been taken from the implementation of `types.listOf`, but has # 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 # 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 # `check` fn as this check is deep/strict, and because `check` runs
# prior to merging. # prior to merging.
merge = loc: defs: merge =
loc: defs:
let let
# Each element of `dupes` is a list. When there are duplicates, # Each element of `dupes` is a list. When there are duplicates,
# later lists will be duplicates of earlier lists, so just throw on # 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 # the first set of duplicates found so that we don't have duplicate
# error msgs. # error msgs.
checked = filter (li: checked = filter (
li:
if length li > 1 then if length li > 1 then
throw '' throw ''
The option `${ The option `${showOption loc}' contains duplicate entries after merging:
showOption loc
}' contains duplicate entries after merging:
${showDefs li}'' ${showDefs li}''
else else
false) dupes; false
dupes = ) dupes;
map (def: filter (def': def'.value == def.value) merged) merged; dupes = map (def: filter (def': def'.value == def.value) merged) merged;
merged = filter (x: x ? value) (concatLists (imap1 (n: def: merged = filter (x: x ? value) (
imap1 (m: el: concatLists (
imap1 (
n: def:
imap1 (
m: el:
let let
inherit (def) file; inherit (def) file;
loc' = loc loc' = loc ++ [ "[definition ${toString n}-entry ${toString m}]" ];
++ [ "[definition ${toString n}-entry ${toString m}]" ]; in
in (mergeDefinitions loc' listType.nestedTypes.elemType [{ (mergeDefinitions loc' listType.nestedTypes.elemType [
{
inherit file; inherit file;
value = el; value = el;
}]).optionalValue // { }
]).optionalValue
// {
inherit loc' file; inherit loc' file;
}) def.value) defs)); }
in deepSeq checked (map (x: x.value) merged); ) def.value
) defs
)
);
in
deepSeq checked (map (x: x.value) merged);
}; };
in { in
StartCalendarInterval = let {
StartCalendarInterval =
let
CalendarIntervalEntry = types.submodule { CalendarIntervalEntry = types.submodule {
options = { options = {
Minute = mkOption { Minute = mkOption {
@ -116,6 +145,6 @@ in {
}; };
}; };
}; };
in types.either CalendarIntervalEntry in
(types'.uniqueList (types.nonEmptyListOf CalendarIntervalEntry)); types.either CalendarIntervalEntry (types'.uniqueList (types.nonEmptyListOf CalendarIntervalEntry));
} }

View file

@ -3,10 +3,11 @@
{ {
assertPlatform = module: pkgs: platforms: { assertPlatform = module: pkgs: platforms: {
assertion = lib.elem pkgs.stdenv.hostPlatform.system platforms; assertion = lib.elem pkgs.stdenv.hostPlatform.system platforms;
message = let message =
platformsStr = lib.concatStringsSep "\n" let
(map (p: " - ${p}") (lib.sort (a: b: a < b) platforms)); platformsStr = lib.concatStringsSep "\n" (map (p: " - ${p}") (lib.sort (a: b: a < b) platforms));
in '' in
''
The module ${module} does not support your platform. It only supports The module ${module} does not support your platform. It only supports
${platformsStr}''; ${platformsStr}'';

View file

@ -1,4 +1,5 @@
{ lib }: { { lib }:
{
# Converts a boolean to a yes/no string. This is used in lots of # Converts a boolean to a yes/no string. This is used in lots of
# configuration formats. # configuration formats.
yesNo = value: if value then "yes" else "no"; yesNo = value: if value then "yes" else "no";

View file

@ -9,13 +9,23 @@
{ lib }: { lib }:
let inherit (lib) all filterAttrs head hm mapAttrs length tail toposort; let
in { inherit (lib)
all
filterAttrs
head
hm
mapAttrs
length
tail
toposort
;
in
{
empty = { }; empty = { };
isEntry = e: e ? data && e ? after && e ? before; isEntry = e: e ? data && e ? after && e ? before;
isDag = dag: isDag = dag: builtins.isAttrs dag && all hm.dag.isEntry (builtins.attrValues dag);
builtins.isAttrs dag && all hm.dag.isEntry (builtins.attrValues dag);
# Takes an attribute set containing entries built by entryAnywhere, # Takes an attribute set containing entries built by entryAnywhere,
# entryAfter, and entryBefore to a topologically sorted list of # entryAfter, and entryBefore to a topologically sorted list of
@ -73,11 +83,10 @@ in {
# ]; # ];
# } # }
# true # true
topoSort = dag: topoSort =
dag:
let let
dagBefore = dag: name: dagBefore = dag: name: builtins.attrNames (filterAttrs (n: v: builtins.elem name v.before) dag);
builtins.attrNames
(filterAttrs (n: v: builtins.elem name v.before) dag);
normalizedDag = mapAttrs (n: v: { normalizedDag = mapAttrs (n: v: {
name = n; name = n;
data = v.data; data = v.data;
@ -85,9 +94,12 @@ in {
}) dag; }) dag;
before = a: b: builtins.elem a.name b.after; before = a: b: builtins.elem a.name b.after;
sorted = toposort before (builtins.attrValues normalizedDag); sorted = toposort before (builtins.attrValues normalizedDag);
in if sorted ? result then { in
if sorted ? result then
{
result = map (v: { inherit (v) name data; }) sorted.result; result = map (v: { inherit (v) name data; }) sorted.result;
} else }
else
sorted; sorted;
# Applies a function to each element of the given DAG. # Applies a function to each element of the given DAG.
@ -107,21 +119,28 @@ in {
# #
# The entries as a whole can be given a relation to other DAG nodes. All # The entries as a whole can be given a relation to other DAG nodes. All
# generated nodes are then placed before or after those dependencies. # generated nodes are then placed before or after those dependencies.
entriesBetween = tag: entriesBetween =
tag:
let let
go = i: before: after: entries: go =
i: before: after: entries:
let let
name = "${tag}-${toString i}"; name = "${tag}-${toString i}";
i' = i + 1; i' = i + 1;
in if entries == [ ] then in
if entries == [ ] then
hm.dag.empty hm.dag.empty
else if length entries == 1 then { else if length entries == 1 then
{
"${name}" = hm.dag.entryBetween before after (head entries); "${name}" = hm.dag.entryBetween before after (head entries);
} else }
else
{ {
"${name}" = hm.dag.entryAfter after (head entries); "${name}" = hm.dag.entryAfter after (head entries);
} // go (i + 1) before [ name ] (tail entries); }
in go 0; // go (i + 1) before [ name ] (tail entries);
in
go 0;
entriesAnywhere = tag: hm.dag.entriesBetween tag [ ] [ ]; entriesAnywhere = tag: hm.dag.entriesBetween tag [ ] [ ];
entriesAfter = tag: hm.dag.entriesBetween tag [ ]; entriesAfter = tag: hm.dag.entriesBetween tag [ ];

View file

@ -1,9 +1,22 @@
{ homeDirectory, lib, pkgs }: {
homeDirectory,
lib,
pkgs,
}:
let let
inherit (lib) inherit (lib)
hasPrefix hm literalExpression mkDefault mkIf mkOption removePrefix types; hasPrefix
in { hm
literalExpression
mkDefault
mkIf
mkOption
removePrefix
types
;
in
{
# Constructs a type suitable for a `home.file` like option. The # Constructs a type suitable for a `home.file` like option. The
# target path may be either absolute or relative, in which case it # target path may be either absolute or relative, in which case it
# is relative the `basePath` argument (which itself must be an # is relative the `basePath` argument (which itself must be an
@ -13,8 +26,12 @@ in {
# - opt the name of the option, for self-references # - opt the name of the option, for self-references
# - basePathDesc docbook compatible description of the base path # - basePathDesc docbook compatible description of the base path
# - basePath the file base path # - basePath the file base path
fileType = opt: basePathDesc: basePath: fileType =
types.attrsOf (types.submodule ({ name, config, ... }: { opt: basePathDesc: basePath:
types.attrsOf (
types.submodule (
{ name, config, ... }:
{
options = { options = {
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
@ -26,9 +43,12 @@ in {
}; };
target = mkOption { target = mkOption {
type = types.str; type = types.str;
apply = p: apply =
let absPath = if hasPrefix "/" p then p else "${basePath}/${p}"; p:
in removePrefix (homeDirectory + "/") absPath; let
absPath = if hasPrefix "/" p then p else "${basePath}/${p}";
in
removePrefix (homeDirectory + "/") absPath;
defaultText = literalExpression "name"; defaultText = literalExpression "name";
description = '' description = ''
Path to target file relative to ${basePathDesc}. Path to target file relative to ${basePathDesc}.
@ -110,11 +130,17 @@ in {
config = { config = {
target = mkDefault name; target = mkDefault name;
source = mkIf (config.text != null) (mkDefault (pkgs.writeTextFile { source = mkIf (config.text != null) (
mkDefault (
pkgs.writeTextFile {
inherit (config) text; inherit (config) text;
executable = config.executable == true; # can be null executable = config.executable == true; # can be null
name = hm.strings.storeFileName name; name = hm.strings.storeFileName name;
})); }
}; )
})); );
};
}
)
);
} }

View file

@ -1,23 +1,41 @@
{ lib }: { lib }:
{ {
toHyprconf = { attrs, indentLevel ? 0, importantPrefixes ? [ "$" ], }: toHyprconf =
{
attrs,
indentLevel ? 0,
importantPrefixes ? [ "$" ],
}:
let let
inherit (lib) inherit (lib)
all concatMapStringsSep concatStrings concatStringsSep filterAttrs foldl all
generators hasPrefix isAttrs isList mapAttrsToList replicate; concatMapStringsSep
concatStrings
concatStringsSep
filterAttrs
foldl
generators
hasPrefix
isAttrs
isList
mapAttrsToList
replicate
;
initialIndent = concatStrings (replicate indentLevel " "); initialIndent = concatStrings (replicate indentLevel " ");
toHyprconf' = indent: attrs: toHyprconf' =
indent: attrs:
let let
sections = sections = filterAttrs (n: v: isAttrs v || (isList v && all isAttrs v)) attrs;
filterAttrs (n: v: isAttrs v || (isList v && all isAttrs v)) attrs;
mkSection = n: attrs: mkSection =
n: attrs:
if lib.isList attrs then if lib.isList attrs then
(concatMapStringsSep "\n" (a: mkSection n a) attrs) (concatMapStringsSep "\n" (a: mkSection n a) attrs)
else '' else
''
${indent}${n} { ${indent}${n} {
${toHyprconf' " ${indent}" attrs}${indent}} ${toHyprconf' " ${indent}" attrs}${indent}}
''; '';
@ -27,47 +45,61 @@
inherit indent; inherit indent;
}; };
allFields = allFields = filterAttrs (n: v: !(isAttrs v || (isList v && all isAttrs v))) attrs;
filterAttrs (n: v: !(isAttrs v || (isList v && all isAttrs v)))
attrs;
isImportantField = n: _: isImportantField =
foldl (acc: prev: if hasPrefix prev n then true else acc) false n: _: foldl (acc: prev: if hasPrefix prev n then true else acc) false importantPrefixes;
importantPrefixes;
importantFields = filterAttrs isImportantField allFields; importantFields = filterAttrs isImportantField allFields;
fields = builtins.removeAttrs allFields fields = builtins.removeAttrs allFields (mapAttrsToList (n: _: n) importantFields);
(mapAttrsToList (n: _: n) importantFields); in
in mkFields importantFields mkFields importantFields
+ concatStringsSep "\n" (mapAttrsToList mkSection sections) + concatStringsSep "\n" (mapAttrsToList mkSection sections)
+ mkFields fields; + mkFields fields;
in toHyprconf' initialIndent attrs; in
toHyprconf' initialIndent attrs;
toKDL = { }: toKDL =
{ }:
let let
inherit (lib) concatStringsSep splitString mapAttrsToList any; inherit (lib)
concatStringsSep
splitString
mapAttrsToList
any
;
inherit (builtins) typeOf replaceStrings elem; inherit (builtins) typeOf replaceStrings elem;
# ListOf String -> String # ListOf String -> String
indentStrings = let indentStrings =
let
# Although the input of this function is a list of strings, # Although the input of this function is a list of strings,
# the strings themselves *will* contain newlines, so you need # the strings themselves *will* contain newlines, so you need
# to normalize the list by joining and resplitting them. # to normalize the list by joining and resplitting them.
unlines = lib.splitString "\n"; unlines = lib.splitString "\n";
lines = lib.concatStringsSep "\n"; lines = lib.concatStringsSep "\n";
indentAll = lines: concatStringsSep "\n" (map (x: " " + x) lines); indentAll = lines: concatStringsSep "\n" (map (x: " " + x) lines);
in stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines)); in
stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines));
# String -> String # String -> String
sanitizeString = replaceStrings [ "\n" ''"'' ] [ "\\n" ''\"'' ]; sanitizeString = replaceStrings [ "\n" ''"'' ] [ "\\n" ''\"'' ];
# OneOf [Int Float String Bool Null] -> String # OneOf [Int Float String Bool Null] -> String
literalValueToString = element: literalValueToString =
element:
lib.throwIfNot lib.throwIfNot
(elem (typeOf element) [ "int" "float" "string" "bool" "null" ]) (elem (typeOf element) [
"int"
"float"
"string"
"bool"
"null"
])
"Cannot convert value of type ${typeOf element} to KDL literal." "Cannot convert value of type ${typeOf element} to KDL literal."
(if typeOf element == "null" then (
if typeOf element == "null" then
"null" "null"
else if element == false then else if element == false then
"false" "false"
@ -76,39 +108,51 @@
else if typeOf element == "string" then else if typeOf element == "string" then
''"${sanitizeString element}"'' ''"${sanitizeString element}"''
else else
toString element); toString element
);
# Attrset Conversion # Attrset Conversion
# String -> AttrsOf Anything -> String # String -> AttrsOf Anything -> String
convertAttrsToKDL = name: attrs: convertAttrsToKDL =
name: attrs:
let let
optArgsString = lib.optionalString (attrs ? "_args") optArgsString = lib.optionalString (attrs ? "_args") (
(lib.pipe attrs._args [ lib.pipe attrs._args [
(map literalValueToString) (map literalValueToString)
(lib.concatStringsSep " ") (lib.concatStringsSep " ")
(s: s + " ") (s: s + " ")
]); ]
);
optPropsString = lib.optionalString (attrs ? "_props") optPropsString = lib.optionalString (attrs ? "_props") (
(lib.pipe attrs._props [ lib.pipe attrs._props [
(lib.mapAttrsToList (lib.mapAttrsToList (name: value: "${name}=${literalValueToString value}"))
(name: value: "${name}=${literalValueToString value}"))
(lib.concatStringsSep " ") (lib.concatStringsSep " ")
(s: s + " ") (s: s + " ")
]); ]
);
children = children = lib.filterAttrs (
lib.filterAttrs (name: _: !(elem name [ "_args" "_props" ])) attrs; name: _:
in '' !(elem name [
"_args"
"_props"
])
) attrs;
in
''
${name} ${optArgsString}${optPropsString}{ ${name} ${optArgsString}${optPropsString}{
${indentStrings (mapAttrsToList convertAttributeToKDL children)} ${indentStrings (mapAttrsToList convertAttributeToKDL children)}
}''; }'';
# List Conversion # List Conversion
# String -> ListOf (OneOf [Int Float String Bool Null]) -> String # String -> ListOf (OneOf [Int Float String Bool Null]) -> String
convertListOfFlatAttrsToKDL = name: list: convertListOfFlatAttrsToKDL =
let flatElements = map literalValueToString list; name: list:
in "${name} ${concatStringsSep " " flatElements}"; let
flatElements = map literalValueToString list;
in
"${name} ${concatStringsSep " " flatElements}";
# String -> ListOf Anything -> String # String -> ListOf Anything -> String
convertListOfNonFlatAttrsToKDL = name: list: '' convertListOfNonFlatAttrsToKDL = name: list: ''
@ -117,18 +161,39 @@
}''; }'';
# String -> ListOf Anything -> String # String -> ListOf Anything -> String
convertListToKDL = name: list: convertListToKDL =
let elementsAreFlat = !any (el: elem (typeOf el) [ "list" "set" ]) list; name: list:
in if elementsAreFlat then let
elementsAreFlat =
!any (
el:
elem (typeOf el) [
"list"
"set"
]
) list;
in
if elementsAreFlat then
convertListOfFlatAttrsToKDL name list convertListOfFlatAttrsToKDL name list
else else
convertListOfNonFlatAttrsToKDL name list; convertListOfNonFlatAttrsToKDL name list;
# Combined Conversion # Combined Conversion
# String -> Anything -> String # String -> Anything -> String
convertAttributeToKDL = name: value: convertAttributeToKDL =
let vType = typeOf value; name: value:
in if elem vType [ "int" "float" "bool" "null" "string" ] then let
vType = typeOf value;
in
if
elem vType [
"int"
"float"
"bool"
"null"
"string"
]
then
"${name} ${literalValueToString value}" "${name} ${literalValueToString value}"
else if vType == "set" then else if vType == "set" then
convertAttrsToKDL name value convertAttrsToKDL name value
@ -139,88 +204,140 @@
Cannot convert type `(${typeOf value})` to KDL: Cannot convert type `(${typeOf value})` to KDL:
${name} = ${toString value} ${name} = ${toString value}
''; '';
in attrs: '' in
attrs: ''
${concatStringsSep "\n" (mapAttrsToList convertAttributeToKDL attrs)} ${concatStringsSep "\n" (mapAttrsToList convertAttributeToKDL attrs)}
''; '';
toSCFG = { }: toSCFG =
{ }:
let let
inherit (lib) concatStringsSep mapAttrsToList any; inherit (lib) concatStringsSep mapAttrsToList any;
inherit (builtins) typeOf replaceStrings elem; inherit (builtins) typeOf replaceStrings elem;
# ListOf String -> String # ListOf String -> String
indentStrings = let indentStrings =
let
# Although the input of this function is a list of strings, # Although the input of this function is a list of strings,
# the strings themselves *will* contain newlines, so you need # the strings themselves *will* contain newlines, so you need
# to normalize the list by joining and resplitting them. # to normalize the list by joining and resplitting them.
unlines = lib.splitString "\n"; unlines = lib.splitString "\n";
lines = lib.concatStringsSep "\n"; lines = lib.concatStringsSep "\n";
indentAll = lines: concatStringsSep "\n" (map (x: " " + x) lines); indentAll = lines: concatStringsSep "\n" (map (x: " " + x) lines);
in stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines)); in
stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines));
# String -> Bool # String -> Bool
specialChars = s: specialChars =
any (char: elem char (reserved ++ [ " " "'" "{" "}" ])) s:
(lib.stringToCharacters s); any (
char:
elem char (
reserved
++ [
" "
"'"
"{"
"}"
]
)
) (lib.stringToCharacters s);
# String -> String # String -> String
sanitizeString = sanitizeString = replaceStrings reserved [
replaceStrings reserved [ ''\"'' "\\\\" "\\r" "\\n" "\\t" ]; ''\"''
"\\\\"
"\\r"
"\\n"
"\\t"
];
reserved = [ ''"'' "\\" "\r" "\n" " " ]; reserved = [
''"''
"\\"
"\r"
"\n"
" "
];
# OneOf [Int Float String Bool] -> String # OneOf [Int Float String Bool] -> String
literalValueToString = element: literalValueToString =
lib.throwIfNot (elem (typeOf element) [ "int" "float" "string" "bool" ]) element:
lib.throwIfNot
(elem (typeOf element) [
"int"
"float"
"string"
"bool"
])
"Cannot convert value of type ${typeOf element} to SCFG literal." "Cannot convert value of type ${typeOf element} to SCFG literal."
(if element == false then (
if element == false then
"false" "false"
else if element == true then else if element == true then
"true" "true"
else if typeOf element == "string" then else if typeOf element == "string" then
if element == "" || specialChars element then if element == "" || specialChars element then ''"${sanitizeString element}"'' else element
''"${sanitizeString element}"''
else else
element toString element
else );
toString element);
# Bool -> ListOf (OneOf [Int Float String Bool]) -> String # Bool -> ListOf (OneOf [Int Float String Bool]) -> String
toOptParamsString = cond: list: toOptParamsString =
lib.optionalString (cond) (lib.pipe list [ cond: list:
lib.optionalString (cond) (
lib.pipe list [
(map literalValueToString) (map literalValueToString)
(concatStringsSep " ") (concatStringsSep " ")
(s: " " + s) (s: " " + s)
]); ]
);
# Attrset Conversion # Attrset Conversion
# String -> AttrsOf Anything -> String # String -> AttrsOf Anything -> String
convertAttrsToSCFG = name: attrs: convertAttrsToSCFG =
name: attrs:
let let
optParamsString = toOptParamsString (attrs ? "_params") attrs._params; optParamsString = toOptParamsString (attrs ? "_params") attrs._params;
in '' in
''
${name}${optParamsString} { ${name}${optParamsString} {
${indentStrings (convertToAttrsSCFG' attrs)} ${indentStrings (convertToAttrsSCFG' attrs)}
}''; }'';
# Attrset Conversion # Attrset Conversion
# AttrsOf Anything -> ListOf String # AttrsOf Anything -> ListOf String
convertToAttrsSCFG' = attrs: convertToAttrsSCFG' =
mapAttrsToList convertAttributeToSCFG attrs:
(lib.filterAttrs (name: val: !isNull val && name != "_params") attrs); mapAttrsToList convertAttributeToSCFG (
lib.filterAttrs (name: val: !isNull val && name != "_params") attrs
);
# List Conversion # List Conversion
# String -> ListOf (OneOf [Int Float String Bool]) -> String # String -> ListOf (OneOf [Int Float String Bool]) -> String
convertListOfFlatAttrsToSCFG = name: list: convertListOfFlatAttrsToSCFG =
let optParamsString = toOptParamsString (list != [ ]) list; name: list:
in "${name}${optParamsString}"; let
optParamsString = toOptParamsString (list != [ ]) list;
in
"${name}${optParamsString}";
# Combined Conversion # Combined Conversion
# String -> Anything -> String # String -> Anything -> String
convertAttributeToSCFG = name: value: convertAttributeToSCFG =
lib.throwIf (name == "") "Directive must not be empty" name: value:
(let vType = typeOf value; lib.throwIf (name == "") "Directive must not be empty" (
in if elem vType [ "int" "float" "bool" "string" ] then let
vType = typeOf value;
in
if
elem vType [
"int"
"float"
"bool"
"string"
]
then
"${name} ${literalValueToString value}" "${name} ${literalValueToString value}"
else if vType == "set" then else if vType == "set" then
convertAttrsToSCFG name value convertAttrsToSCFG name value
@ -230,8 +347,10 @@
throw '' throw ''
Cannot convert type `(${typeOf value})` to SCFG: Cannot convert type `(${typeOf value})` to SCFG:
${name} = ${toString value} ${name} = ${toString value}
''); ''
in attrs: );
in
attrs:
lib.optionalString (attrs != { }) '' lib.optionalString (attrs != { }) ''
${concatStringsSep "\n" (convertToAttrsSCFG' attrs)} ${concatStringsSep "\n" (convertToAttrsSCFG' attrs)}
''; '';

View file

@ -7,7 +7,13 @@
let let
inherit (lib) inherit (lib)
concatMapStringsSep concatStrings escape hasPrefix head replaceStrings; concatMapStringsSep
concatStrings
escape
hasPrefix
head
replaceStrings
;
mkPrimitive = t: v: { mkPrimitive = t: v: {
_type = "gvariant"; _type = "gvariant";
@ -36,7 +42,8 @@ let
# Returns the GVariant type of a given Nix value. If no type can be # Returns the GVariant type of a given Nix value. If no type can be
# found for the value then the empty string is returned. # found for the value then the empty string is returned.
typeOf = v: typeOf =
v:
with type; with type;
if builtins.isBool v then if builtins.isBool v then
boolean boolean
@ -47,29 +54,27 @@ let
else if builtins.isString v then else if builtins.isString v then
string string
else if builtins.isList v then else if builtins.isList v then
let elemType = elemTypeOf v; let
in if elemType == "" then "" else arrayOf elemType elemType = elemTypeOf v;
in
if elemType == "" then "" else arrayOf elemType
else if builtins.isAttrs v && v ? type then else if builtins.isAttrs v && v ? type then
v.type v.type
else else
""; "";
elemTypeOf = vs: elemTypeOf = vs: if builtins.isList vs then if vs == [ ] then "" else typeOf (head vs) else "";
if builtins.isList vs then
if vs == [ ] then "" else typeOf (head vs)
else
"";
mkMaybe = elemType: elem: mkMaybe =
mkPrimitive (type.maybeOf elemType) elem // { elemType: elem:
__toString = self: mkPrimitive (type.maybeOf elemType) elem
if self.value == null then // {
"@${self.type} nothing" __toString =
else self: if self.value == null then "@${self.type} nothing" else "just ${toString self.value}";
"just ${toString self.value}";
}; };
in rec { in
rec {
inherit type typeOf; inherit type typeOf;
@ -83,7 +88,8 @@ in rec {
# Returns the GVariant value that most closely matches the given Nix # Returns the GVariant value that most closely matches the given Nix
# value. If no GVariant value can be found then `null` is returned. # value. If no GVariant value can be found then `null` is returned.
mkValue = v: mkValue =
v:
if builtins.isBool v then if builtins.isBool v then
mkBoolean v mkBoolean v
else if builtins.isInt v then else if builtins.isInt v then
@ -99,55 +105,77 @@ in rec {
else else
null; null;
mkArray = elemType: elems: mkArray =
mkPrimitive (type.arrayOf elemType) (map mkValue elems) // { elemType: elems:
__toString = self: mkPrimitive (type.arrayOf elemType) (map mkValue elems)
"@${self.type} [${concatMapStringsSep "," toString self.value}]"; // {
__toString = self: "@${self.type} [${concatMapStringsSep "," toString self.value}]";
}; };
mkEmptyArray = elemType: mkArray elemType [ ]; mkEmptyArray = elemType: mkArray elemType [ ];
mkVariant = elem: mkVariant =
let gvarElem = mkValue elem; elem:
in mkPrimitive type.variant gvarElem // { let
gvarElem = mkValue elem;
in
mkPrimitive type.variant gvarElem
// {
__toString = self: "@${self.type} <${toString self.value}>"; __toString = self: "@${self.type} <${toString self.value}>";
}; };
mkDictionaryEntry = elems: mkDictionaryEntry =
elems:
let let
gvarElems = map mkValue elems; gvarElems = map mkValue elems;
dictionaryType = type.dictionaryEntryOf (map (e: e.type) gvarElems); dictionaryType = type.dictionaryEntryOf (map (e: e.type) gvarElems);
in mkPrimitive dictionaryType gvarElems // { in
__toString = self: mkPrimitive dictionaryType gvarElems
"@${self.type} {${concatMapStringsSep "," toString self.value}}"; // {
__toString = self: "@${self.type} {${concatMapStringsSep "," toString self.value}}";
}; };
mkNothing = elemType: mkMaybe elemType null; mkNothing = elemType: mkMaybe elemType null;
mkJust = elem: let gvarElem = mkValue elem; in mkMaybe gvarElem.type gvarElem; mkJust =
elem:
let
gvarElem = mkValue elem;
in
mkMaybe gvarElem.type gvarElem;
mkTuple = elems: mkTuple =
elems:
let let
gvarElems = map mkValue elems; gvarElems = map mkValue elems;
tupleType = type.tupleOf (map (e: e.type) gvarElems); tupleType = type.tupleOf (map (e: e.type) gvarElems);
in mkPrimitive tupleType gvarElems // { in
__toString = self: mkPrimitive tupleType gvarElems
"@${self.type} (${concatMapStringsSep "," toString self.value})"; // {
__toString = self: "@${self.type} (${concatMapStringsSep "," toString self.value})";
}; };
mkBoolean = v: mkBoolean =
mkPrimitive type.boolean v // { v:
mkPrimitive type.boolean v
// {
__toString = self: if self.value then "true" else "false"; __toString = self: if self.value then "true" else "false";
}; };
mkString = v: mkString =
let sanitize = s: replaceStrings [ "\n" ] [ "\\n" ] (escape [ "'" "\\" ] s); v:
in mkPrimitive type.string v // { let
sanitize = s: replaceStrings [ "\n" ] [ "\\n" ] (escape [ "'" "\\" ] s);
in
mkPrimitive type.string v
// {
__toString = self: "'${sanitize self.value}'"; __toString = self: "'${sanitize self.value}'";
}; };
mkObjectpath = v: mkObjectpath =
mkPrimitive type.string v // { v:
mkPrimitive type.string v
// {
__toString = self: "objectpath '${escape [ "'" ] self.value}'"; __toString = self: "objectpath '${escape [ "'" ] self.value}'";
}; };
@ -157,8 +185,10 @@ in rec {
mkUint16 = mkPrimitive type.uint16; mkUint16 = mkPrimitive type.uint16;
mkInt32 = v: mkInt32 =
mkPrimitive type.int32 v // { v:
mkPrimitive type.int32 v
// {
__toString = self: toString self.value; __toString = self: toString self.value;
}; };
@ -168,8 +198,10 @@ in rec {
mkUint64 = mkPrimitive type.uint64; mkUint64 = mkPrimitive type.uint64;
mkDouble = v: mkDouble =
mkPrimitive type.double v // { v:
mkPrimitive type.double v
// {
__toString = self: toString self.value; __toString = self: toString self.value;
}; };

View file

@ -107,10 +107,12 @@
github = "d-dervishi"; github = "d-dervishi";
githubId = 61125355; githubId = 61125355;
name = "David Dervishi"; name = "David Dervishi";
keys = [{ keys = [
{
longKeyId = "rsa4096/0xB1C012F0E7697195"; longKeyId = "rsa4096/0xB1C012F0E7697195";
fingerprint = "4C92 E3B0 21B5 5562 A1E0 CE3D B1C0 12F0 E769 7195"; fingerprint = "4C92 E3B0 21B5 5562 A1E0 CE3D B1C0 12F0 E769 7195";
}]; }
];
}; };
Dines97 = { Dines97 = {
name = "Denis Kaynar"; name = "Denis Kaynar";
@ -147,8 +149,7 @@
email = "yiheng.he@proton.me"; email = "yiheng.he@proton.me";
matrix = "@hey2022:matrix.org"; matrix = "@hey2022:matrix.org";
github = "hey2022"; github = "hey2022";
keys = keys = [ { fingerprint = "128E 09C0 6F73 D678 6BB5 E551 5EA5 3C75 F7BE 3EDE"; } ];
[{ fingerprint = "128E 09C0 6F73 D678 6BB5 E551 5EA5 3C75 F7BE 3EDE"; }];
}; };
jack5079 = { jack5079 = {
name = "Jack W."; name = "Jack W.";
@ -167,10 +168,12 @@
name = "Jessica"; name = "Jessica";
email = "jess+nix@jessie.cafe"; email = "jess+nix@jessie.cafe";
githubId = 43591752; githubId = 43591752;
keys = [{ keys = [
{
longkeyid = "rsa3072/0xBA3350686C918606"; longkeyid = "rsa3072/0xBA3350686C918606";
fingerprint = "8092 3BD1 ECD0 E436 671D C8E9 BA33 5068 6C91 8606"; fingerprint = "8092 3BD1 ECD0 E436 671D C8E9 BA33 5068 6C91 8606";
}]; }
];
}; };
jkarlson = { jkarlson = {
email = "jekarlson@gmail.com"; email = "jekarlson@gmail.com";
@ -250,10 +253,12 @@
email = "kamadorueda@gmail.com"; email = "kamadorueda@gmail.com";
github = "kamadorueda"; github = "kamadorueda";
githubId = 47480384; githubId = 47480384;
keys = [{ keys = [
{
longkeyid = "rsa4096/0x04D0CEAF916A9A40"; longkeyid = "rsa4096/0x04D0CEAF916A9A40";
fingerprint = "2BE3 BAFD 793E A349 ED1F F00F 04D0 CEAF 916A 9A40"; fingerprint = "2BE3 BAFD 793E A349 ED1F F00F 04D0 CEAF 916A 9A40";
}]; }
];
}; };
katexochen = { katexochen = {
name = "Paul Meyer"; name = "Paul Meyer";
@ -339,20 +344,24 @@
email = "nick@hassan.host"; email = "nick@hassan.host";
github = "n-hass"; github = "n-hass";
githubId = 72363381; githubId = 72363381;
keys = [{ keys = [
{
longkeyid = "rsa4096/0xFC95AB946A781EE7"; longkeyid = "rsa4096/0xFC95AB946A781EE7";
fingerprint = "FDEE 6116 DBA7 8840 7323 4466 A371 5973 2728 A6A6"; fingerprint = "FDEE 6116 DBA7 8840 7323 4466 A371 5973 2728 A6A6";
}]; }
];
}; };
seylerius = { seylerius = {
email = "sable@seyleri.us"; email = "sable@seyleri.us";
name = "Sable Seyler"; name = "Sable Seyler";
github = "seylerius"; github = "seylerius";
githubId = 1145981; githubId = 1145981;
keys = [{ keys = [
{
logkeyid = "rsa4096/0x68BF2EAE6D91CAFF"; logkeyid = "rsa4096/0x68BF2EAE6D91CAFF";
fingerprint = "F0E0 0311 126A CD72 4392 25E6 68BF 2EAE 6D91 CAFF"; fingerprint = "F0E0 0311 126A CD72 4392 25E6 68BF 2EAE 6D91 CAFF";
}]; }
];
}; };
silmarp = { silmarp = {
name = "Silmar Pereira da Silva Junior"; name = "Silmar Pereira da Silva Junior";
@ -394,10 +403,12 @@
github = "msfjarvis"; github = "msfjarvis";
githubId = "13348378"; githubId = "13348378";
name = "Harsh Shandilya"; name = "Harsh Shandilya";
keys = [{ keys = [
{
longkeyid = "rsa4096/0xB7843F823355E9B9"; longkeyid = "rsa4096/0xB7843F823355E9B9";
fingerprint = "8F87 050B 0F9C B841 1515 7399 B784 3F82 3355 E9B9"; fingerprint = "8F87 050B 0F9C B841 1515 7399 B784 3F82 3355 E9B9";
}]; }
];
}; };
ambroisie = { ambroisie = {
email = "bruno.home-manager@belanyi.fr"; email = "bruno.home-manager@belanyi.fr";
@ -571,10 +582,12 @@
email = "88944439+rcerc@users.noreply.github.com"; email = "88944439+rcerc@users.noreply.github.com";
github = "rcerc"; github = "rcerc";
githubId = 88944439; githubId = 88944439;
keys = [{ keys = [
{
longkeyid = "ed25519/0x3F98EC7EC2B87ED1"; longkeyid = "ed25519/0x3F98EC7EC2B87ED1";
fingerprint = "D5D6 FD1F 0D9A 3284 FB9B C26D 3F98 EC7E C2B8 7ED1"; fingerprint = "D5D6 FD1F 0D9A 3284 FB9B C26D 3F98 EC7E C2B8 7ED1";
}]; }
];
}; };
mtoohey = { mtoohey = {
name = "Matthew Toohey"; name = "Matthew Toohey";
@ -594,8 +607,7 @@
matrix = "@soywod:matrix.org"; matrix = "@soywod:matrix.org";
github = "soywod"; github = "soywod";
githubId = 10437171; githubId = 10437171;
keys = keys = [ { fingerprint = "75F0 AB7C FE01 D077 AEE6 CAFD 353E 4A18 EE0F AB72"; } ];
[{ fingerprint = "75F0 AB7C FE01 D077 AEE6 CAFD 353E 4A18 EE0F AB72"; }];
}; };
tensor5 = { tensor5 = {
github = "tensor5"; github = "tensor5";
@ -615,8 +627,7 @@
github = "toastal"; github = "toastal";
githubId = 561087; githubId = 561087;
name = "toastal"; name = "toastal";
keys = keys = [ { fingerprint = "7944 74B7 D236 DAB9 C9EF E7F9 5CCE 6F14 66D4 7C9E"; } ];
[{ fingerprint = "7944 74B7 D236 DAB9 C9EF E7F9 5CCE 6F14 66D4 7C9E"; }];
}; };
tomodachi94 = { tomodachi94 = {
email = "tomodachi94+nixpkgs@protonmail.com"; email = "tomodachi94+nixpkgs@protonmail.com";
@ -683,8 +694,7 @@
email = "git+nix@cleslie.uk"; email = "git+nix@cleslie.uk";
github = "callumio"; github = "callumio";
githubId = 16057677; githubId = 16057677;
keys = keys = [ { fingerprint = "BC82 4BB5 1656 D144 285E A0EC D382 C4AF EECE AA90"; } ];
[{ fingerprint = "BC82 4BB5 1656 D144 285E A0EC D382 C4AF EECE AA90"; }];
}; };
ALameLlama = { ALameLlama = {
name = "Nicholas Ciechanowski"; name = "Nicholas Ciechanowski";
@ -703,10 +713,12 @@
email = "me@hpsaucii.dev"; email = "me@hpsaucii.dev";
github = "HPsaucii"; github = "HPsaucii";
githubId = 126502193; githubId = 126502193;
keys = [{ keys = [
{
longkeyid = "rsa4096/0xEDB2C634166AE6AD"; longkeyid = "rsa4096/0xEDB2C634166AE6AD";
fingerprint = "AD32 73D4 5E0E 9478 E826 543F EDB2 C634 166A E6AD"; fingerprint = "AD32 73D4 5E0E 9478 E826 543F EDB2 C634 166A E6AD";
}]; }
];
}; };
folliehiyuki = { folliehiyuki = {
name = "Hoang Nguyen"; name = "Hoang Nguyen";

View file

@ -1,19 +1,31 @@
{ lib }: rec { { lib }:
rec {
mkNushellInline = expr: lib.setType "nushell-inline" { inherit expr; }; mkNushellInline = expr: lib.setType "nushell-inline" { inherit expr; };
isNushellInline = lib.isType "nushell-inline"; isNushellInline = lib.isType "nushell-inline";
toNushell = { indent ? "", multiline ? true, asBindings ? false, }@args: toNushell =
{
indent ? "",
multiline ? true,
asBindings ? false,
}@args:
v: v:
let let
innerIndent = "${indent} "; innerIndent = "${indent} ";
introSpace = if multiline then '' introSpace =
if multiline then
''
${innerIndent}'' else ${innerIndent}''
else
" "; " ";
outroSpace = if multiline then '' outroSpace =
if multiline then
''
${indent}'' else ${indent}''
else
" "; " ";
innerArgs = args // { innerArgs = args // {
indent = if asBindings then indent else innerIndent; indent = if asBindings then indent else innerIndent;
@ -21,36 +33,41 @@
}; };
concatItems = lib.concatStringsSep introSpace; concatItems = lib.concatStringsSep introSpace;
generatedBindings = assert lib.assertMsg (badVarNames == [ ]) generatedBindings =
"Bad Nushell variable names: ${ assert lib.assertMsg (badVarNames == [ ])
lib.generators.toPretty { } badVarNames "Bad Nushell variable names: ${lib.generators.toPretty { } badVarNames}";
}"; lib.concatStrings (
lib.concatStrings (lib.mapAttrsToList (key: value: '' lib.mapAttrsToList (key: value: ''
${indent}let ${key} = ${toNushell innerArgs value} ${indent}let ${key} = ${toNushell innerArgs value}
'') v); '') v
);
isBadVarName = name: isBadVarName =
name:
# Extracted from https://github.com/nushell/nushell/blob/ebc7b80c23f777f70c5053cca428226b3fe00d30/crates/nu-parser/src/parser.rs#L33 # Extracted from https://github.com/nushell/nushell/blob/ebc7b80c23f777f70c5053cca428226b3fe00d30/crates/nu-parser/src/parser.rs#L33
# Variables with numeric or even empty names are allowed. The only requisite is not containing any of the following characters # Variables with numeric or even empty names are allowed. The only requisite is not containing any of the following characters
let invalidVariableCharacters = ".[({+-*^/=!<>&|"; let
in lib.match "^[$]?[^${lib.escapeRegex invalidVariableCharacters}]+$" invalidVariableCharacters = ".[({+-*^/=!<>&|";
name == null; in
lib.match "^[$]?[^${lib.escapeRegex invalidVariableCharacters}]+$" name == null;
badVarNames = lib.filter isBadVarName (builtins.attrNames v); badVarNames = lib.filter isBadVarName (builtins.attrNames v);
in if asBindings then in
if asBindings then
generatedBindings generatedBindings
else if v == null then else if v == null then
"null" "null"
else if lib.isInt v || lib.isFloat v || lib.isString v || lib.isBool v then else if lib.isInt v || lib.isFloat v || lib.isString v || lib.isBool v then
lib.strings.toJSON v lib.strings.toJSON v
else if lib.isList v then else if lib.isList v then
(if v == [ ] then (
if v == [ ] then
"[]" "[]"
else else
"[${introSpace}${ "[${introSpace}${concatItems (map (value: "${toNushell innerArgs value}") v)}${outroSpace}]"
concatItems (map (value: "${toNushell innerArgs value}") v) )
}${outroSpace}]")
else if lib.isAttrs v then else if lib.isAttrs v then
(if isNushellInline v then (
if isNushellInline v then
"(${v.expr})" "(${v.expr})"
else if v == { } then else if v == { } then
"{}" "{}"
@ -58,9 +75,11 @@
toString v toString v
else else
"{${introSpace}${ "{${introSpace}${
concatItems (lib.mapAttrsToList (key: value: concatItems (
"${lib.strings.toJSON key}: ${toNushell innerArgs value}") v) lib.mapAttrsToList (key: value: "${lib.strings.toJSON key}: ${toNushell innerArgs value}") v
}${outroSpace}}") )
}${outroSpace}}"
)
else else
abort "nushell.toNushell: type ${lib.typeOf v} is unsupported"; abort "nushell.toNushell: type ${lib.typeOf v} is unsupported";
} }

View file

@ -2,27 +2,35 @@
let let
mkShellIntegrationOption = name: mkShellIntegrationOption =
{ config, baseName ? name, extraDescription ? "" }: name:
let attrName = "enable${baseName}Integration"; {
in lib.mkOption { config,
baseName ? name,
extraDescription ? "",
}:
let
attrName = "enable${baseName}Integration";
in
lib.mkOption {
default = config.home.shell.${attrName}; default = config.home.shell.${attrName};
defaultText = lib.literalMD "[](#opt-home.shell.${attrName})"; defaultText = lib.literalMD "[](#opt-home.shell.${attrName})";
example = false; example = false;
description = "Whether to enable ${name} integration.${ description = "Whether to enable ${name} integration.${
lib.optionalString (extraDescription != "") lib.optionalString (extraDescription != "") ("\n\n" + extraDescription)
("\n\n" + extraDescription)
}"; }";
type = lib.types.bool; type = lib.types.bool;
}; };
in rec { in
rec {
# Produces a Bourne shell like statement that prepend new values to # Produces a Bourne shell like statement that prepend new values to
# an possibly existing variable, using sep(arator). # an possibly existing variable, using sep(arator).
# Example: # Example:
# prependToVar ":" "PATH" [ "$HOME/bin" "$HOME/.local/bin" ] # prependToVar ":" "PATH" [ "$HOME/bin" "$HOME/.local/bin" ]
# => "$HOME/bin:$HOME/.local/bin:${PATH:+:}\$PATH" # => "$HOME/bin:$HOME/.local/bin:${PATH:+:}\$PATH"
prependToVar = sep: n: v: prependToVar =
sep: n: v:
"${lib.concatStringsSep sep v}\${${n}:+${sep}}\$${n}"; "${lib.concatStringsSep sep v}\${${n}:+${sep}}\$${n}";
# Produces a Bourne shell like variable export statement. # Produces a Bourne shell like variable export statement.

View file

@ -3,11 +3,15 @@
nixpkgsLib: nixpkgsLib:
let mkHmLib = import ./.; let
in nixpkgsLib.extend (self: super: { mkHmLib = import ./.;
in
nixpkgsLib.extend (
self: super: {
hm = mkHmLib { lib = self; }; hm = mkHmLib { lib = self; };
# For forward compatibility. # For forward compatibility.
literalExpression = super.literalExpression or super.literalExample; literalExpression = super.literalExpression or super.literalExample;
literalDocBook = super.literalDocBook or super.literalExample; literalDocBook = super.literalDocBook or super.literalExample;
}) }
)

View file

@ -2,22 +2,39 @@
let let
inherit (lib) inherit (lib)
genList length lowerChars replaceStrings stringToCharacters upperChars; genList
in { length
lowerChars
replaceStrings
stringToCharacters
upperChars
;
in
{
# Figures out a valid Nix store name for the given path. # Figures out a valid Nix store name for the given path.
storeFileName = path: storeFileName =
path:
let let
# All characters that are considered safe. Note "-" is not # All characters that are considered safe. Note "-" is not
# included to avoid "-" followed by digit being interpreted as a # included to avoid "-" followed by digit being interpreted as a
# version. # version.
safeChars = [ "+" "." "_" "?" "=" ] ++ lowerChars ++ upperChars safeChars =
[
"+"
"."
"_"
"?"
"="
]
++ lowerChars
++ upperChars
++ stringToCharacters "0123456789"; ++ stringToCharacters "0123456789";
empties = l: genList (x: "") (length l); empties = l: genList (x: "") (length l);
unsafeInName = unsafeInName = stringToCharacters (replaceStrings safeChars (empties safeChars) path);
stringToCharacters (replaceStrings safeChars (empties safeChars) path);
safeName = replaceStrings unsafeInName (empties unsafeInName) path; safeName = replaceStrings unsafeInName (empties unsafeInName) path;
in "hm_" + safeName; in
"hm_" + safeName;
} }

View file

@ -2,13 +2,32 @@
let let
inherit (lib) inherit (lib)
concatStringsSep defaultFunctor fixedWidthNumber hm imap1 isAttrs isList concatStringsSep
length listToAttrs mapAttrs mkIf mkOrder mkOption mkOptionType nameValuePair defaultFunctor
stringLength types warn; fixedWidthNumber
hm
imap1
isAttrs
isList
length
listToAttrs
mapAttrs
mkIf
mkOrder
mkOption
mkOptionType
nameValuePair
stringLength
types
warn
;
dagEntryOf = elemType: dagEntryOf =
elemType:
let let
submoduleType = types.submodule ({ name, ... }: { submoduleType = types.submodule (
{ name, ... }:
{
options = { options = {
data = mkOption { type = elemType; }; data = mkOption { type = elemType; };
after = mkOption { type = with types; listOf str; }; after = mkOption { type = with types; listOf str; };
@ -17,27 +36,31 @@ let
config = mkIf (elemType.name == "submodule") { config = mkIf (elemType.name == "submodule") {
data._module.args.dagName = name; data._module.args.dagName = name;
}; };
}); }
maybeConvert = def: );
maybeConvert =
def:
if hm.dag.isEntry def.value then if hm.dag.isEntry def.value then
def.value def.value
else else
hm.dag.entryAnywhere (if def ? priority then hm.dag.entryAnywhere (if def ? priority then mkOrder def.priority def.value else def.value);
mkOrder def.priority def.value in
else mkOptionType {
def.value);
in mkOptionType {
name = "dagEntryOf"; name = "dagEntryOf";
description = "DAG entry of ${elemType.description}"; description = "DAG entry of ${elemType.description}";
# leave the checking to the submodule type # leave the checking to the submodule type
merge = loc: defs: merge =
submoduleType.merge loc (map (def: { loc: defs:
submoduleType.merge loc (
map (def: {
inherit (def) file; inherit (def) file;
value = maybeConvert def; value = maybeConvert def;
}) defs); }) defs
);
}; };
in rec { in
rec {
# A directed acyclic graph of some inner type. # A directed acyclic graph of some inner type.
# #
# Note, if the element type is a submodule then the `name` argument # Note, if the element type is a submodule then the `name` argument
@ -45,16 +68,21 @@ in rec {
# internal structure of the DAG values. To give access to the # internal structure of the DAG values. To give access to the
# "actual" attribute name a new submodule argument is provided with # "actual" attribute name a new submodule argument is provided with
# the name `dagName`. # the name `dagName`.
dagOf = elemType: dagOf =
let attrEquivalent = types.attrsOf (dagEntryOf elemType); elemType:
in mkOptionType rec { let
attrEquivalent = types.attrsOf (dagEntryOf elemType);
in
mkOptionType rec {
name = "dagOf"; name = "dagOf";
description = "DAG of ${elemType.description}"; description = "DAG of ${elemType.description}";
inherit (attrEquivalent) check merge emptyValue; inherit (attrEquivalent) check merge emptyValue;
getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "<name>" ]); getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "<name>" ]);
getSubModules = elemType.getSubModules; getSubModules = elemType.getSubModules;
substSubModules = m: dagOf (elemType.substSubModules m); substSubModules = m: dagOf (elemType.substSubModules m);
functor = (defaultFunctor name) // { wrapped = elemType; }; functor = (defaultFunctor name) // {
wrapped = elemType;
};
nestedTypes.elemType = elemType; nestedTypes.elemType = elemType;
}; };
} }

View file

@ -1,10 +1,28 @@
{ lib, gvariant ? import ./gvariant.nix { inherit lib; } }: {
lib,
gvariant ? import ./gvariant.nix { inherit lib; },
}:
let let
inherit (lib) inherit (lib)
all concatMap foldl' getFiles getValues head isFunction literalExpression all
mergeAttrs mergeDefaultOption mergeOneOption mergeOptions mkOption concatMap
mkOptionType showFiles showOption types; foldl'
getFiles
getValues
head
isFunction
literalExpression
mergeAttrs
mergeDefaultOption
mergeOneOption
mergeOptions
mkOption
mkOptionType
showFiles
showOption
types
;
typesDag = import ./types-dag.nix { inherit lib; }; typesDag = import ./types-dag.nix { inherit lib; };
@ -12,24 +30,30 @@ let
# must refer back to the type. # must refer back to the type.
gvar = gvariant; gvar = gvariant;
in rec { in
rec {
inherit (typesDag) dagOf; inherit (typesDag) dagOf;
selectorFunction = mkOptionType { selectorFunction = mkOptionType {
name = "selectorFunction"; name = "selectorFunction";
description = "Function that takes an attribute set and returns a list" description =
"Function that takes an attribute set and returns a list"
+ " containing a selection of the values of the input set"; + " containing a selection of the values of the input set";
check = isFunction; check = isFunction;
merge = _loc: defs: as: concatMap (select: select as) (getValues defs); merge =
_loc: defs: as:
concatMap (select: select as) (getValues defs);
}; };
overlayFunction = mkOptionType { overlayFunction = mkOptionType {
name = "overlayFunction"; name = "overlayFunction";
description = "An overlay function, takes self and super and returns" description =
"An overlay function, takes self and super and returns"
+ " an attribute set overriding the desired attributes."; + " an attribute set overriding the desired attributes.";
check = isFunction; check = isFunction;
merge = _loc: defs: self: super: merge =
_loc: defs: self: super:
foldl' (res: def: mergeAttrs res (def.value self super)) { } defs; foldl' (res: def: mergeAttrs res (def.value self super)) { } defs;
}; };
@ -69,26 +93,32 @@ in rec {
name = "gvariant"; name = "gvariant";
description = "GVariant value"; description = "GVariant value";
check = v: gvar.mkValue v != null; check = v: gvar.mkValue v != null;
merge = loc: defs: merge =
loc: defs:
let let
vdefs = map (d: vdefs = map (
d // { d:
value = d
if gvar.isGVariant d.value then d.value else gvar.mkValue d.value; // {
}) defs; value = if gvar.isGVariant d.value then d.value else gvar.mkValue d.value;
}
) defs;
vals = map (d: d.value) vdefs; vals = map (d: d.value) vdefs;
defTypes = map (x: x.type) vals; defTypes = map (x: x.type) vals;
sameOrNull = x: y: if x == y then y else null; sameOrNull = x: y: if x == y then y else null;
# A bit naive to just check the first entry… # A bit naive to just check the first entry…
sharedDefType = foldl' sameOrNull (head defTypes) defTypes; sharedDefType = foldl' sameOrNull (head defTypes) defTypes;
allChecked = all (x: check x) vals; allChecked = all (x: check x) vals;
in if sharedDefType == null then in
throw ("Cannot merge definitions of `${showOption loc}' with" if sharedDefType == null then
throw (
"Cannot merge definitions of `${showOption loc}' with"
+ " mismatched GVariant types given in" + " mismatched GVariant types given in"
+ " ${showFiles (getFiles defs)}.") + " ${showFiles (getFiles defs)}."
)
else if gvar.isArray sharedDefType && allChecked then else if gvar.isArray sharedDefType && allChecked then
gvar.mkValue ((types.listOf gvariant).merge loc gvar.mkValue ((types.listOf gvariant).merge loc (map (d: d // { value = d.value.value; }) vdefs))
(map (d: d // { value = d.value.value; }) vdefs)) // { // {
type = sharedDefType; type = sharedDefType;
} }
else if gvar.isTuple sharedDefType && allChecked then else if gvar.isTuple sharedDefType && allChecked then
@ -107,8 +137,10 @@ in rec {
mergeDefaultOption loc defs; mergeDefaultOption loc defs;
}; };
nushellValue = let nushellValue =
valueType = types.nullOr (types.oneOf [ let
valueType = types.nullOr (
types.oneOf [
(lib.mkOptionType { (lib.mkOptionType {
name = "nushell"; name = "nushell";
description = "Nushell inline value"; description = "Nushell inline value";
@ -120,14 +152,22 @@ in rec {
types.float types.float
types.str types.str
types.path types.path
(types.attrsOf valueType // { (
types.attrsOf valueType
// {
description = "attribute set of Nushell values"; description = "attribute set of Nushell values";
descriptionClass = "name"; descriptionClass = "name";
}) }
(types.listOf valueType // { )
(
types.listOf valueType
// {
description = "list of Nushell values"; description = "list of Nushell values";
descriptionClass = "name"; descriptionClass = "name";
}) }
]); )
in valueType; ]
);
in
valueType;
} }

View file

@ -2,7 +2,8 @@
rec { rec {
# Produces a Zsh shell like value # Produces a Zsh shell like value
toZshValue = v: toZshValue =
v:
if builtins.isBool v then if builtins.isBool v then
if v then "true" else "false" if v then "true" else "false"
else if builtins.isString v then else if builtins.isString v then

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
@ -9,7 +14,8 @@ let
inherit (config.home.version) release isReleaseBranch; inherit (config.home.version) release isReleaseBranch;
}; };
in { in
{
options = { options = {
manual.html.enable = lib.mkOption { manual.html.enable = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
@ -51,7 +57,10 @@ in {
config = { config = {
home.packages = lib.mkMerge [ home.packages = lib.mkMerge [
(lib.mkIf cfg.html.enable [ docs.manual.html docs.manual.htmlOpenTool ]) (lib.mkIf cfg.html.enable [
docs.manual.html
docs.manual.htmlOpenTool
])
(lib.mkIf cfg.manpages.enable [ docs.manPages ]) (lib.mkIf cfg.manpages.enable [ docs.manPages ])
(lib.mkIf cfg.json.enable [ docs.options.json ]) (lib.mkIf cfg.json.enable [ docs.options.json ])
]; ];

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) types; inherit (lib) types;
@ -7,18 +12,23 @@ let
toDconfIni = lib.generators.toINI { mkKeyValue = mkIniKeyValue; }; toDconfIni = lib.generators.toINI { mkKeyValue = mkIniKeyValue; };
mkIniKeyValue = key: value: mkIniKeyValue = key: value: "${key}=${toString (lib.hm.gvariant.mkValue value)}";
"${key}=${toString (lib.hm.gvariant.mkValue value)}";
# The dconf keys managed by this configuration. We store this as part of the # The dconf keys managed by this configuration. We store this as part of the
# generation state to be able to reset keys that become unmanaged during # generation state to be able to reset keys that become unmanaged during
# switch. # switch.
stateDconfKeys = pkgs.writeText "dconf-keys.json" (builtins.toJSON stateDconfKeys = pkgs.writeText "dconf-keys.json" (
(lib.concatLists (lib.mapAttrsToList builtins.toJSON (
(dir: entries: lib.mapAttrsToList (key: _: "/${dir}/${key}") entries) lib.concatLists (
cfg.settings))); lib.mapAttrsToList (
dir: entries: lib.mapAttrsToList (key: _: "/${dir}/${key}") entries
) cfg.settings
)
)
);
in { in
{
meta.maintainers = [ lib.maintainers.rycee ]; meta.maintainers = [ lib.maintainers.rycee ];
options = { options = {
@ -84,8 +94,8 @@ in {
ln -s ${stateDconfKeys} $out/state/${stateDconfKeys.name} ln -s ${stateDconfKeys} $out/state/${stateDconfKeys.name}
''; '';
home.activation.dconfSettings = lib.hm.dag.entryAfter [ "installPackages" ] home.activation.dconfSettings = lib.hm.dag.entryAfter [ "installPackages" ] (
(let let
iniFile = pkgs.writeText "hm-dconf.ini" (toDconfIni cfg.settings); iniFile = pkgs.writeText "hm-dconf.ini" (toDconfIni cfg.settings);
statePath = "state/${stateDconfKeys.name}"; statePath = "state/${stateDconfKeys.name}";
@ -95,7 +105,12 @@ in {
${config.lib.bash.initHomeManagerLib} ${config.lib.bash.initHomeManagerLib}
PATH=${lib.makeBinPath [ pkgs.dconf pkgs.jq ]}''${PATH:+:}$PATH PATH=${
lib.makeBinPath [
pkgs.dconf
pkgs.jq
]
}''${PATH:+:}$PATH
oldState="$1" oldState="$1"
newState="$2" newState="$2"
@ -116,7 +131,8 @@ in {
run $DCONF_DBUS_RUN_SESSION dconf reset "$key" run $DCONF_DBUS_RUN_SESSION dconf reset "$key"
done done
''; '';
in '' in
''
if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then
export DCONF_DBUS_RUN_SESSION="" export DCONF_DBUS_RUN_SESSION=""
else else
@ -132,6 +148,7 @@ in {
run $DCONF_DBUS_RUN_SESSION ${pkgs.dconf}/bin/dconf load / < ${iniFile} run $DCONF_DBUS_RUN_SESSION ${pkgs.dconf}/bin/dconf load / < ${iniFile}
unset DCONF_DBUS_RUN_SESSION unset DCONF_DBUS_RUN_SESSION
''); ''
);
}; };
} }

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
@ -6,7 +11,8 @@ let
iniFormat = pkgs.formats.ini { }; iniFormat = pkgs.formats.ini { };
in { in
{
meta.maintainers = with lib.maintainers; [ loicreynier ]; meta.maintainers = with lib.maintainers; [ loicreynier ];
options.editorconfig = { options.editorconfig = {
@ -38,12 +44,16 @@ in {
}; };
config = lib.mkIf (cfg.enable && cfg.settings != { }) { config = lib.mkIf (cfg.enable && cfg.settings != { }) {
home.file.".editorconfig".text = let home.file.".editorconfig".text =
let
renderedSettings = lib.generators.toINIWithGlobalSection { } { renderedSettings = lib.generators.toINIWithGlobalSection { } {
globalSection = { root = true; }; globalSection = {
root = true;
};
sections = cfg.settings; sections = cfg.settings;
}; };
in '' in
''
# Generated by Home Manager # Generated by Home Manager
${renderedSettings} ${renderedSettings}
''; '';

View file

@ -2,7 +2,12 @@
# #
# https://github.com/NixOS/nixpkgs/blob/23.11/nixos/modules/config/fonts/fontconfig.nix # https://github.com/NixOS/nixpkgs/blob/23.11/nixos/modules/config/fonts/fontconfig.nix
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
@ -10,15 +15,19 @@ let
profileDirectory = config.home.profileDirectory; profileDirectory = config.home.profileDirectory;
in { in
{
meta.maintainers = [ lib.maintainers.rycee ]; meta.maintainers = [ lib.maintainers.rycee ];
imports = [ imports = [
(lib.mkRenamedOptionModule [ "fonts" "fontconfig" "enableProfileFonts" ] [ (lib.mkRenamedOptionModule
[ "fonts" "fontconfig" "enableProfileFonts" ]
[
"fonts" "fonts"
"fontconfig" "fontconfig"
"enable" "enable"
]) ]
)
]; ];
options = { options = {
@ -117,7 +126,8 @@ in {
fi fi
''; '';
xdg.configFile = let xdg.configFile =
let
mkFontconfigConf = conf: '' mkFontconfigConf = conf: ''
<?xml version='1.0'?> <?xml version='1.0'?>
@ -128,7 +138,8 @@ in {
${conf} ${conf}
</fontconfig> </fontconfig>
''; '';
in { in
{
"fontconfig/conf.d/10-hm-fonts.conf".text = mkFontconfigConf '' "fontconfig/conf.d/10-hm-fonts.conf".text = mkFontconfigConf ''
<description>Add fonts in the Nix user profile</description> <description>Add fonts in the Nix user profile</description>
@ -143,21 +154,24 @@ in {
<cachedir>${config.home.path}/lib/fontconfig/cache</cachedir> <cachedir>${config.home.path}/lib/fontconfig/cache</cachedir>
''; '';
"fontconfig/conf.d/52-hm-default-fonts.conf".text = let "fontconfig/conf.d/52-hm-default-fonts.conf".text =
genDefault = fonts: name: let
genDefault =
fonts: name:
lib.optionalString (fonts != [ ]) '' lib.optionalString (fonts != [ ]) ''
<alias binding="same"> <alias binding="same">
<family>${name}</family> <family>${name}</family>
<prefer> <prefer>
${ ${lib.concatStringsSep "" (
lib.concatStringsSep "" (map (font: '' map (font: ''
<family>${font}</family> <family>${font}</family>
'') fonts) '') fonts
} )}
</prefer> </prefer>
</alias> </alias>
''; '';
in mkFontconfigConf '' in
mkFontconfigConf ''
<!-- Default fonts --> <!-- Default fonts -->
${genDefault cfg.defaultFonts.sansSerif "sans-serif"} ${genDefault cfg.defaultFonts.sansSerif "sans-serif"}
${genDefault cfg.defaultFonts.serif "serif"} ${genDefault cfg.defaultFonts.serif "serif"}

View file

@ -1,7 +1,12 @@
{ config, lib, ... }: { config, lib, ... }:
let let
inherit (lib) literalExpression mkOption optionalAttrs types; inherit (lib)
literalExpression
mkOption
optionalAttrs
types
;
cfg = config.gtk; cfg = config.gtk;
cfg2 = config.gtk.gtk2; cfg2 = config.gtk.gtk2;
@ -9,22 +14,26 @@ let
cfg4 = config.gtk.gtk4; cfg4 = config.gtk.gtk4;
toGtk3Ini = lib.generators.toINI { toGtk3Ini = lib.generators.toINI {
mkKeyValue = key: value: mkKeyValue =
key: value:
let let
value' = value' = if lib.isBool value then lib.boolToString value else toString value;
if lib.isBool value then lib.boolToString value else toString value; in
in "${lib.escape [ "=" ] key}=${value'}"; "${lib.escape [ "=" ] key}=${value'}";
}; };
formatGtk2Option = n: v: formatGtk2Option =
n: v:
let let
v' = if lib.isBool v then v' =
if lib.isBool v then
lib.boolToString lib.value lib.boolToString lib.value
else if lib.isString v then else if lib.isString v then
''"${v}"'' ''"${v}"''
else else
toString v; toString v;
in "${lib.escape [ "=" ] n} = ${v'}"; in
"${lib.escape [ "=" ] n} = ${v'}";
themeType = types.submodule { themeType = types.submodule {
options = { options = {
@ -100,7 +109,8 @@ let
}; };
}; };
in { in
{
meta.maintainers = [ lib.maintainers.rycee ]; meta.maintainers = [ lib.maintainers.rycee ];
imports = [ imports = [
@ -153,10 +163,8 @@ in {
configLocation = mkOption { configLocation = mkOption {
type = types.path; type = types.path;
default = "${config.home.homeDirectory}/.gtkrc-2.0"; default = "${config.home.homeDirectory}/.gtkrc-2.0";
defaultText = defaultText = literalExpression ''"''${config.home.homeDirectory}/.gtkrc-2.0"'';
literalExpression ''"''${config.home.homeDirectory}/.gtkrc-2.0"''; example = literalExpression ''"''${config.xdg.configHome}/gtk-2.0/gtkrc"'';
example =
literalExpression ''"''${config.xdg.configHome}/gtk-2.0/gtkrc"'';
description = '' description = ''
The location to put the GTK configuration file. The location to put the GTK configuration file.
''; '';
@ -172,7 +180,13 @@ in {
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = with types; attrsOf (oneOf [ bool int str ]); type =
with types;
attrsOf (oneOf [
bool
int
str
]);
default = { }; default = { };
example = { example = {
gtk-cursor-blink = false; gtk-cursor-blink = false;
@ -220,18 +234,24 @@ in {
}; };
}; };
config = lib.mkIf cfg.enable (let config = lib.mkIf cfg.enable (
gtkIni = optionalAttrs (cfg.font != null) { let
gtkIni =
optionalAttrs (cfg.font != null) {
gtk-font-name = gtk-font-name =
let fontSize = if cfg.font.size != null then cfg.font.size else 10; let
in "${cfg.font.name} ${toString fontSize}"; fontSize = if cfg.font.size != null then cfg.font.size else 10;
} // optionalAttrs (cfg.theme != null) { gtk-theme-name = cfg.theme.name; } in
"${cfg.font.name} ${toString fontSize}";
}
// optionalAttrs (cfg.theme != null) { gtk-theme-name = cfg.theme.name; }
// optionalAttrs (cfg.iconTheme != null) { // optionalAttrs (cfg.iconTheme != null) {
gtk-icon-theme-name = cfg.iconTheme.name; gtk-icon-theme-name = cfg.iconTheme.name;
} // optionalAttrs (cfg.cursorTheme != null) { }
// optionalAttrs (cfg.cursorTheme != null) {
gtk-cursor-theme-name = cfg.cursorTheme.name; gtk-cursor-theme-name = cfg.cursorTheme.name;
} // optionalAttrs }
(cfg.cursorTheme != null && cfg.cursorTheme.size != null) { // optionalAttrs (cfg.cursorTheme != null && cfg.cursorTheme.size != null) {
gtk-cursor-theme-size = cfg.cursorTheme.size; gtk-cursor-theme-size = cfg.cursorTheme.size;
}; };
@ -242,25 +262,31 @@ in {
* It does however respect user CSS, so import the theme from here. * It does however respect user CSS, so import the theme from here.
**/ **/
@import url("file://${cfg.theme.package}/share/themes/${cfg.theme.name}/gtk-4.0/gtk.css"); @import url("file://${cfg.theme.package}/share/themes/${cfg.theme.name}/gtk-4.0/gtk.css");
'' + cfg4.extraCss; ''
+ cfg4.extraCss;
dconfIni = optionalAttrs (cfg.font != null) { dconfIni =
optionalAttrs (cfg.font != null) {
font-name = font-name =
let fontSize = if cfg.font.size != null then cfg.font.size else 10; let
in "${cfg.font.name} ${toString fontSize}"; fontSize = if cfg.font.size != null then cfg.font.size else 10;
} // optionalAttrs (cfg.theme != null) { gtk-theme = cfg.theme.name; } in
"${cfg.font.name} ${toString fontSize}";
}
// optionalAttrs (cfg.theme != null) { gtk-theme = cfg.theme.name; }
// optionalAttrs (cfg.iconTheme != null) { // optionalAttrs (cfg.iconTheme != null) {
icon-theme = cfg.iconTheme.name; icon-theme = cfg.iconTheme.name;
} // optionalAttrs (cfg.cursorTheme != null) { }
// optionalAttrs (cfg.cursorTheme != null) {
cursor-theme = cfg.cursorTheme.name; cursor-theme = cfg.cursorTheme.name;
} // optionalAttrs }
(cfg.cursorTheme != null && cfg.cursorTheme.size != null) { // optionalAttrs (cfg.cursorTheme != null && cfg.cursorTheme.size != null) {
cursor-size = cfg.cursorTheme.size; cursor-size = cfg.cursorTheme.size;
}; };
optionalPackage = opt: optionalPackage = opt: lib.optional (opt != null && opt.package != null) opt.package;
lib.optional (opt != null && opt.package != null) opt.package; in
in { {
home.packages = lib.concatMap optionalPackage [ home.packages = lib.concatMap optionalPackage [
cfg.font cfg.font
cfg.theme cfg.theme
@ -268,27 +294,26 @@ in {
cfg.cursorTheme cfg.cursorTheme
]; ];
home.file.${cfg2.configLocation}.text = lib.concatMapStrings (l: l + "\n") home.file.${cfg2.configLocation}.text =
(lib.mapAttrsToList formatGtk2Option gtkIni) + cfg2.extraConfig + "\n"; lib.concatMapStrings (l: l + "\n") (lib.mapAttrsToList formatGtk2Option gtkIni)
+ cfg2.extraConfig
+ "\n";
home.sessionVariables.GTK2_RC_FILES = cfg2.configLocation; home.sessionVariables.GTK2_RC_FILES = cfg2.configLocation;
xdg.configFile."gtk-3.0/settings.ini".text = xdg.configFile."gtk-3.0/settings.ini".text = toGtk3Ini { Settings = gtkIni // cfg3.extraConfig; };
toGtk3Ini { Settings = gtkIni // cfg3.extraConfig; };
xdg.configFile."gtk-3.0/gtk.css" = xdg.configFile."gtk-3.0/gtk.css" = lib.mkIf (cfg3.extraCss != "") { text = cfg3.extraCss; };
lib.mkIf (cfg3.extraCss != "") { text = cfg3.extraCss; };
xdg.configFile."gtk-3.0/bookmarks" = lib.mkIf (cfg3.bookmarks != [ ]) { xdg.configFile."gtk-3.0/bookmarks" = lib.mkIf (cfg3.bookmarks != [ ]) {
text = lib.concatMapStrings (l: l + "\n") cfg3.bookmarks; text = lib.concatMapStrings (l: l + "\n") cfg3.bookmarks;
}; };
xdg.configFile."gtk-4.0/settings.ini".text = xdg.configFile."gtk-4.0/settings.ini".text = toGtk3Ini { Settings = gtkIni // cfg4.extraConfig; };
toGtk3Ini { Settings = gtkIni // cfg4.extraConfig; };
xdg.configFile."gtk-4.0/gtk.css" = xdg.configFile."gtk-4.0/gtk.css" = lib.mkIf (gtk4Css != "") { text = gtk4Css; };
lib.mkIf (gtk4Css != "") { text = gtk4Css; };
dconf.settings."org/gnome/desktop/interface" = dconfIni; dconf.settings."org/gnome/desktop/interface" = dconfIni;
}); }
);
} }

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (pkgs.stdenv) isDarwin; inherit (pkgs.stdenv) isDarwin;
@ -10,16 +15,16 @@ let
(pkgs.writeTextDir "lib/mozilla/native-messaging-hosts/.keep" "") (pkgs.writeTextDir "lib/mozilla/native-messaging-hosts/.keep" "")
]; ];
thunderbirdNativeMessagingHostsPath = if isDarwin then thunderbirdNativeMessagingHostsPath =
"Library/Mozilla/NativeMessagingHosts" if isDarwin then "Library/Mozilla/NativeMessagingHosts" else ".mozilla/native-messaging-hosts";
else
".mozilla/native-messaging-hosts";
firefoxNativeMessagingHostsPath = if isDarwin then firefoxNativeMessagingHostsPath =
if isDarwin then
"Library/Application Support/Mozilla/NativeMessagingHosts" "Library/Application Support/Mozilla/NativeMessagingHosts"
else else
".mozilla/native-messaging-hosts"; ".mozilla/native-messaging-hosts";
in { in
{
meta.maintainers = with lib.maintainers; [ meta.maintainers = with lib.maintainers; [
booxter booxter
rycee rycee
@ -46,9 +51,11 @@ in {
}; };
}; };
config = lib.mkIf (cfg.firefoxNativeMessagingHosts != [ ] config =
|| cfg.thunderbirdNativeMessagingHosts != [ ]) { lib.mkIf (cfg.firefoxNativeMessagingHosts != [ ] || cfg.thunderbirdNativeMessagingHosts != [ ])
home.file = if isDarwin then {
home.file =
if isDarwin then
let let
firefoxNativeMessagingHostsJoined = pkgs.symlinkJoin { firefoxNativeMessagingHostsJoined = pkgs.symlinkJoin {
name = "ff-native-messaging-hosts"; name = "ff-native-messaging-hosts";
@ -58,18 +65,15 @@ in {
name = "th-native-messaging-hosts"; name = "th-native-messaging-hosts";
paths = defaultPaths ++ cfg.thunderbirdNativeMessagingHosts; paths = defaultPaths ++ cfg.thunderbirdNativeMessagingHosts;
}; };
in { in
"${thunderbirdNativeMessagingHostsPath}" = {
lib.mkIf (cfg.thunderbirdNativeMessagingHosts != [ ]) { "${thunderbirdNativeMessagingHostsPath}" = lib.mkIf (cfg.thunderbirdNativeMessagingHosts != [ ]) {
source = source = "${thunderbirdNativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
"${thunderbirdNativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
recursive = true; recursive = true;
}; };
"${firefoxNativeMessagingHostsPath}" = "${firefoxNativeMessagingHostsPath}" = lib.mkIf (cfg.firefoxNativeMessagingHosts != [ ]) {
lib.mkIf (cfg.firefoxNativeMessagingHosts != [ ]) { source = "${firefoxNativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
source =
"${firefoxNativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
recursive = true; recursive = true;
}; };
} }
@ -78,13 +82,12 @@ in {
nativeMessagingHostsJoined = pkgs.symlinkJoin { nativeMessagingHostsJoined = pkgs.symlinkJoin {
name = "mozilla-native-messaging-hosts"; name = "mozilla-native-messaging-hosts";
# on Linux, the directory is shared between Firefox and Thunderbird; merge both into one # on Linux, the directory is shared between Firefox and Thunderbird; merge both into one
paths = defaultPaths ++ cfg.firefoxNativeMessagingHosts paths = defaultPaths ++ cfg.firefoxNativeMessagingHosts ++ cfg.thunderbirdNativeMessagingHosts;
++ cfg.thunderbirdNativeMessagingHosts;
}; };
in { in
{
"${firefoxNativeMessagingHostsPath}" = { "${firefoxNativeMessagingHostsPath}" = {
source = source = "${nativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
"${nativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
recursive = true; recursive = true;
}; };
}; };

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkOption types; inherit (lib) mkOption types;
@ -7,7 +12,9 @@ let
hostPlatform = pkgs.stdenv.hostPlatform; hostPlatform = pkgs.stdenv.hostPlatform;
entryModule = types.submodule ({ config, ... }: { entryModule = types.submodule (
{ config, ... }:
{
options = { options = {
id = mkOption { id = mkOption {
internal = true; internal = true;
@ -44,21 +51,25 @@ let
config = { config = {
id = lib.mkDefault (builtins.hashString "sha256" config.message); id = lib.mkDefault (builtins.hashString "sha256" config.message);
}; };
}); }
);
isNixFile = n: v: v == "regular" && lib.hasSuffix ".nix" n; isNixFile = n: v: v == "regular" && lib.hasSuffix ".nix" n;
# builtins.attrNames return the values in alphabetical order # builtins.attrNames return the values in alphabetical order
newsFiles = newsFiles = builtins.attrNames (lib.filterAttrs isNixFile (builtins.readDir ./news));
builtins.attrNames (lib.filterAttrs isNixFile (builtins.readDir ./news)); newsEntries = builtins.map (newsFile: import (./news + "/${newsFile}")) newsFiles;
newsEntries = in
builtins.map (newsFile: import (./news + "/${newsFile}")) newsFiles; {
in {
meta.maintainers = [ lib.maintainers.rycee ]; meta.maintainers = [ lib.maintainers.rycee ];
options = { options = {
news = { news = {
display = mkOption { display = mkOption {
type = types.enum [ "silent" "notify" "show" ]; type = types.enum [
"silent"
"notify"
"show"
];
default = "notify"; default = "notify";
description = '' description = ''
How unread and relevant news should be presented when How unread and relevant news should be presented when
@ -100,8 +111,9 @@ in {
}; };
config = { config = {
news.json.output = pkgs.writeText "hm-news.json" news.json.output = pkgs.writeText "hm-news.json" (
(builtins.toJSON { inherit (cfg) display entries; }); builtins.toJSON { inherit (cfg) display entries; }
);
# DO NOT define new entries here, instead use the `./create-news-entry.sh` # DO NOT define new entries here, instead use the `./create-news-entry.sh`
# script and create an individual news file inside `news` sub-directory. # script and create an individual news file inside `news` sub-directory.
@ -250,8 +262,7 @@ in {
{ {
time = "2021-09-23T17:04:48+00:00"; time = "2021-09-23T17:04:48+00:00";
condition = hostPlatform.isLinux condition = hostPlatform.isLinux && config.services.screen-locker.enable;
&& config.services.screen-locker.enable;
message = '' message = ''
'xautolock' is now optional in 'services.screen-locker', and the 'xautolock' is now optional in 'services.screen-locker', and the
'services.screen-locker' options have been reorganized for clarity. 'services.screen-locker' options have been reorganized for clarity.
@ -1699,9 +1710,12 @@ in {
{ {
time = "2024-06-26T07:07:17+00:00"; time = "2024-06-26T07:07:17+00:00";
condition = with config.programs.yazi; condition =
enable && (enableBashIntegration || enableZshIntegration with config.programs.yazi;
|| enableFishIntegration || enableNushellIntegration); enable
&& (
enableBashIntegration || enableZshIntegration || enableFishIntegration || enableNushellIntegration
);
message = '' message = ''
Yazi's shell integration wrappers have been renamed from 'ya' to 'yy'. Yazi's shell integration wrappers have been renamed from 'ya' to 'yy'.
@ -1881,10 +1895,12 @@ in {
{ {
time = "2024-12-04T20:00:00+00:00"; time = "2024-12-04T20:00:00+00:00";
condition = let condition =
let
sCfg = config.programs.starship; sCfg = config.programs.starship;
fCfg = config.programs.fish; fCfg = config.programs.fish;
in sCfg.enable && sCfg.enableFishIntegration && fCfg.enable; in
sCfg.enable && sCfg.enableFishIntegration && fCfg.enable;
message = '' message = ''
A new option 'programs.starship.enableInteractive' is available for A new option 'programs.starship.enableInteractive' is available for
the Fish shell that only enables starship if the shell is interactive. the Fish shell that only enables starship if the shell is interactive.
@ -1894,10 +1910,11 @@ in {
} }
{ {
time = "2024-12-08T17:22:13+00:00"; time = "2024-12-08T17:22:13+00:00";
condition = let condition =
usingMbsync = lib.any (a: a.mbsync.enable) let
(lib.attrValues config.accounts.email.accounts); usingMbsync = lib.any (a: a.mbsync.enable) (lib.attrValues config.accounts.email.accounts);
in usingMbsync; in
usingMbsync;
message = '' message = ''
isync/mbsync 1.5.0 has changed several things. isync/mbsync 1.5.0 has changed several things.

View file

@ -1,12 +1,38 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) inherit (lib)
boolToString concatStringsSep escape floatToString getVersion isBool boolToString
isConvertibleWithToString isDerivation isFloat isInt isList isString concatStringsSep
literalExpression maintainers mapAttrsToList mkDefault mkEnableOption mkIf escape
mkMerge mkOption optionalString toPretty types versionAtLeast; floatToString
getVersion
isBool
isConvertibleWithToString
isDerivation
isFloat
isInt
isList
isString
literalExpression
maintainers
mapAttrsToList
mkDefault
mkEnableOption
mkIf
mkMerge
mkOption
optionalString
toPretty
types
versionAtLeast
;
cfg = config.nix; cfg = config.nix;
@ -16,9 +42,9 @@ let
nixPath = concatStringsSep ":" cfg.nixPath; nixPath = concatStringsSep ":" cfg.nixPath;
useXdg = config.nix.enable useXdg = config.nix.enable && (config.nix.settings.use-xdg-base-directories or false);
&& (config.nix.settings.use-xdg-base-directories or false); defexprDir =
defexprDir = if useXdg then if useXdg then
"${config.xdg.stateHome}/nix/defexpr" "${config.xdg.stateHome}/nix/defexpr"
else else
"${config.home.homeDirectory}/.nix-defexpr"; "${config.home.homeDirectory}/.nix-defexpr";
@ -28,17 +54,21 @@ let
# they'll be read relative to each other. # they'll be read relative to each other.
channelPath = "${defexprDir}/50-home-manager"; channelPath = "${defexprDir}/50-home-manager";
channelsDrv = let channelsDrv =
let
mkEntry = name: drv: { mkEntry = name: drv: {
inherit name; inherit name;
path = toString drv; path = toString drv;
}; };
in pkgs.linkFarm "channels" (lib.mapAttrsToList mkEntry cfg.channels); in
pkgs.linkFarm "channels" (lib.mapAttrsToList mkEntry cfg.channels);
nixConf = assert isNixAtLeast "2.2"; nixConf =
assert isNixAtLeast "2.2";
let let
mkValueString = v: mkValueString =
v:
if v == null then if v == null then
"" ""
else if isInt v then else if isInt v then
@ -62,10 +92,10 @@ let
mkKeyValue = k: v: "${escape [ "=" ] k} = ${mkValueString v}"; mkKeyValue = k: v: "${escape [ "=" ] k} = ${mkValueString v}";
mkKeyValuePairs = attrs: mkKeyValuePairs = attrs: concatStringsSep "\n" (mapAttrsToList mkKeyValue attrs);
concatStringsSep "\n" (mapAttrsToList mkKeyValue attrs);
in pkgs.writeTextFile { in
pkgs.writeTextFile {
name = "nix.conf"; name = "nix.conf";
text = '' text = ''
# WARNING: this file is generated from the nix.settings option in # WARNING: this file is generated from the nix.settings option in
@ -75,45 +105,55 @@ let
${cfg.extraOptions} ${cfg.extraOptions}
''; '';
checkPhase = checkPhase =
if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then '' if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then
''
echo "Ignoring validation for cross-compilation" echo "Ignoring validation for cross-compilation"
'' else ''
else
let let
showCommand = showCommand = if isNixAtLeast "2.20pre" then "config show" else "show-config";
if isNixAtLeast "2.20pre" then "config show" else "show-config"; in
in '' ''
echo "Validating generated nix.conf" echo "Validating generated nix.conf"
ln -s $out ./nix.conf ln -s $out ./nix.conf
set -e set -e
set +o pipefail set +o pipefail
NIX_CONF_DIR=$PWD \ NIX_CONF_DIR=$PWD \
${cfg.package}/bin/nix ${showCommand} ${ ${cfg.package}/bin/nix ${showCommand} ${optionalString (isNixAtLeast "2.3pre") "--no-net --option experimental-features nix-command"} \
optionalString (isNixAtLeast "2.3pre")
"--no-net --option experimental-features nix-command"
} \
|& sed -e 's/^warning:/error:/' \ |& sed -e 's/^warning:/error:/' \
| (! grep '${ | (! grep '${if cfg.checkConfig then "^error:" else "^error: unknown setting"}')
if cfg.checkConfig then "^error:" else "^error: unknown setting"
}')
set -o pipefail set -o pipefail
''; '';
}; };
semanticConfType = with types; semanticConfType =
with types;
let let
confAtom = nullOr (oneOf [ bool int float str path package ]) // { confAtom =
description = nullOr (oneOf [
"Nix config atom (null, bool, int, float, str, path or package)"; bool
int
float
str
path
package
])
// {
description = "Nix config atom (null, bool, int, float, str, path or package)";
}; };
in attrsOf (either confAtom (listOf confAtom)); in
attrsOf (either confAtom (listOf confAtom));
jsonFormat = pkgs.formats.json { }; jsonFormat = pkgs.formats.json { };
in { in
{
options.nix = { options.nix = {
enable = mkEnableOption '' enable =
mkEnableOption ''
the Nix configuration module the Nix configuration module
'' // { ''
// {
default = true; default = true;
visible = false; visible = false;
}; };
@ -169,10 +209,20 @@ in {
}; };
registry = mkOption { registry = mkOption {
type = types.attrsOf (types.submodule (let type = types.attrsOf (
inputAttrs = types.attrsOf types.submodule (
(types.oneOf [ types.str types.int types.bool types.package ]); let
in { config, name, ... }: { inputAttrs = types.attrsOf (
types.oneOf [
types.str
types.int
types.bool
types.package
]
);
in
{ config, name, ... }:
{
options = { options = {
from = mkOption { from = mkOption {
type = inputAttrs; type = inputAttrs;
@ -189,8 +239,7 @@ in {
owner = "my-org"; owner = "my-org";
repo = "my-nixpkgs"; repo = "my-nixpkgs";
}; };
description = description = "The flake reference to which {option}`from>` is to be rewritten.";
"The flake reference to which {option}`from>` is to be rewritten.";
}; };
flake = mkOption { flake = mkOption {
type = types.nullOr types.attrs; type = types.nullOr types.attrs;
@ -215,14 +264,19 @@ in {
type = "indirect"; type = "indirect";
id = name; id = name;
}; };
to = mkIf (config.flake != null) ({ to = mkIf (config.flake != null) (
{
type = "path"; type = "path";
path = config.flake.outPath; path = config.flake.outPath;
} // lib.filterAttrs (n: v: }
n == "lastModified" || n == "rev" || n == "revCount" || n // lib.filterAttrs (
== "narHash") config.flake); n: v: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash"
) config.flake
);
}; };
})); }
)
);
default = { }; default = { };
description = '' description = ''
User level flake registry. User level flake registry.
@ -290,22 +344,22 @@ in {
}) })
(mkIf (cfg.registry != { }) { (mkIf (cfg.registry != { }) {
xdg.configFile."nix/registry.json".source = xdg.configFile."nix/registry.json".source = jsonFormat.generate "registry.json" {
jsonFormat.generate "registry.json" {
version = cfg.registryVersion; version = cfg.registryVersion;
flakes = flakes = mapAttrsToList (n: v: { inherit (v) from to exact; }) cfg.registry;
mapAttrsToList (n: v: { inherit (v) from to exact; }) cfg.registry;
}; };
}) })
(mkIf (cfg.settings != { } || cfg.extraOptions != "") { (mkIf (cfg.settings != { } || cfg.extraOptions != "") {
assertions = [{ assertions = [
{
assertion = cfg.package != null; assertion = cfg.package != null;
message = '' message = ''
A corresponding Nix package must be specified via `nix.package` for generating A corresponding Nix package must be specified via `nix.package` for generating
nix.conf. nix.conf.
''; '';
}]; }
];
xdg.configFile."nix/nix.conf".source = nixConf; xdg.configFile."nix/nix.conf".source = nixConf;
}) })

View file

@ -1,13 +1,23 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.nixGL; cfg = config.nixGL;
wrapperListMarkdown = with builtins; wrapperListMarkdown =
foldl' (list: name: with builtins;
list + '' foldl' (
list: name:
list
+ ''
- ${name} - ${name}
'') "" (attrNames config.lib.nixGL.wrappers); ''
in { ) "" (attrNames config.lib.nixGL.wrappers);
in
{
meta.maintainers = [ lib.maintainers.smona ]; meta.maintainers = [ lib.maintainers.smona ];
options.nixGL = { options.nixGL = {
@ -93,7 +103,12 @@ in {
}; };
prime.installScript = lib.mkOption { prime.installScript = lib.mkOption {
type = with lib.types; nullOr (enum [ "mesa" "nvidia" ]); type =
with lib.types;
nullOr (enum [
"mesa"
"nvidia"
]);
default = null; default = null;
example = "mesa"; example = "mesa";
description = '' description = ''
@ -109,10 +124,12 @@ in {
}; };
installScripts = lib.mkOption { installScripts = lib.mkOption {
type = with lib.types; type = with lib.types; nullOr (listOf (enum (builtins.attrNames config.lib.nixGL.wrappers)));
nullOr (listOf (enum (builtins.attrNames config.lib.nixGL.wrappers)));
default = null; default = null;
example = [ "mesa" "mesaPrime" ]; example = [
"mesa"
"mesaPrime"
];
description = '' description = ''
For each wrapper `wrp` named in the provided list, a wrapper script For each wrapper `wrp` named in the provided list, a wrapper script
named `nixGLWrp` is installed into the environment. These scripts are named `nixGLWrp` is installed into the environment. These scripts are
@ -137,8 +154,10 @@ in {
}; };
}; };
config = let config =
findWrapperPackage = packageAttr: let
findWrapperPackage =
packageAttr:
# NixGL has wrapper packages in different places depending on how you # NixGL has wrapper packages in different places depending on how you
# access it. We want HM configuration to be the same, regardless of how # access it. We want HM configuration to be the same, regardless of how
# NixGL is imported. # NixGL is imported.
@ -157,28 +176,41 @@ in {
else else
throw "Incompatible NixGL package layout"; throw "Incompatible NixGL package layout";
getWrapperExe = vendor: getWrapperExe =
vendor:
let let
glPackage = findWrapperPackage "nixGL${vendor}"; glPackage = findWrapperPackage "nixGL${vendor}";
glExe = lib.getExe glPackage; glExe = lib.getExe glPackage;
vulkanPackage = findWrapperPackage "nixVulkan${vendor}"; vulkanPackage = findWrapperPackage "nixVulkan${vendor}";
vulkanExe = if cfg.vulkan.enable then lib.getExe vulkanPackage else ""; vulkanExe = if cfg.vulkan.enable then lib.getExe vulkanPackage else "";
in "${glExe} ${vulkanExe}"; in
"${glExe} ${vulkanExe}";
mesaOffloadEnv = { "DRI_PRIME" = "${cfg.prime.card}"; }; mesaOffloadEnv = {
"DRI_PRIME" = "${cfg.prime.card}";
};
nvOffloadEnv = { nvOffloadEnv =
{
"DRI_PRIME" = "${cfg.prime.card}"; "DRI_PRIME" = "${cfg.prime.card}";
"__NV_PRIME_RENDER_OFFLOAD" = "1"; "__NV_PRIME_RENDER_OFFLOAD" = "1";
"__GLX_VENDOR_LIBRARY_NAME" = "nvidia"; "__GLX_VENDOR_LIBRARY_NAME" = "nvidia";
"__VK_LAYER_NV_optimus" = "NVIDIA_only"; "__VK_LAYER_NV_optimus" = "NVIDIA_only";
} // (let provider = cfg.prime.nvidiaProvider; }
in if !isNull provider then { // (
let
provider = cfg.prime.nvidiaProvider;
in
if !isNull provider then
{
"__NV_PRIME_RENDER_OFFLOAD_PROVIDER" = "${provider}"; "__NV_PRIME_RENDER_OFFLOAD_PROVIDER" = "${provider}";
} else }
{ }); else
{ }
);
makePackageWrapper = vendor: environment: pkg: makePackageWrapper =
vendor: environment: pkg:
if builtins.isNull cfg.packages then if builtins.isNull cfg.packages then
pkg pkg
else else
@ -191,27 +223,29 @@ in {
# a new debug output to be produced. We won't be producing any debug info # a new debug output to be produced. We won't be producing any debug info
# for the original package. # for the original package.
separateDebugInfo = false; separateDebugInfo = false;
nativeBuildInputs = old.nativeBuildInputs or [ ] nativeBuildInputs = old.nativeBuildInputs or [ ] ++ [ pkgs.makeWrapper ];
++ [ pkgs.makeWrapper ]; buildCommand =
buildCommand = let let
# We need an intermediate wrapper package because makeWrapper # We need an intermediate wrapper package because makeWrapper
# requires a single executable as the wrapper. # requires a single executable as the wrapper.
combinedWrapperPkg = combinedWrapperPkg = pkgs.writeShellScriptBin "nixGLCombinedWrapper-${vendor}" ''
pkgs.writeShellScriptBin "nixGLCombinedWrapper-${vendor}" ''
exec ${getWrapperExe vendor} "$@" exec ${getWrapperExe vendor} "$@"
''; '';
in '' in
''
set -eo pipefail set -eo pipefail
${ # Heavily inspired by https://stackoverflow.com/a/68523368/6259505 ${
lib.concatStringsSep "\n" (map (outputName: '' # Heavily inspired by https://stackoverflow.com/a/68523368/6259505
lib.concatStringsSep "\n" (
map (outputName: ''
echo "Copying output ${outputName}" echo "Copying output ${outputName}"
set -x set -x
cp -rs --no-preserve=mode "${ cp -rs --no-preserve=mode "${pkg.${outputName}}" "''$${outputName}"
pkg.${outputName}
}" "''$${outputName}"
set +x set +x
'') (old.outputs or [ "out" ]))} '') (old.outputs or [ "out" ])
)
}
rm -rf $out/bin/* rm -rf $out/bin/*
shopt -s nullglob # Prevent loop from running if no files shopt -s nullglob # Prevent loop from running if no files
@ -222,10 +256,9 @@ in {
"$out/bin/$prog" \ "$out/bin/$prog" \
--argv0 "$prog" \ --argv0 "$prog" \
--add-flags "$file" \ --add-flags "$file" \
${ ${lib.concatStringsSep " " (
lib.concatStringsSep " " (lib.attrsets.mapAttrsToList lib.attrsets.mapAttrsToList (var: val: "--set '${var}' '${val}'") environment
(var: val: "--set '${var}' '${val}'") environment) )}
}
done done
# If .desktop files refer to the old package, replace the references # If .desktop files refer to the old package, replace the references
@ -240,14 +273,14 @@ in {
shopt -u nullglob # Revert nullglob back to its normal default state shopt -u nullglob # Revert nullglob back to its normal default state
''; '';
})) // { }))
// {
# When the nixGL-wrapped package is given to a HM module, the module # When the nixGL-wrapped package is given to a HM module, the module
# might want to override the package arguments, but our wrapper # might want to override the package arguments, but our wrapper
# wouldn't know what to do with them. So, we rewrite the override # wouldn't know what to do with them. So, we rewrite the override
# function to instead forward the arguments to the package's own # function to instead forward the arguments to the package's own
# override function. # override function.
override = args: override = args: makePackageWrapper vendor environment (pkg.override args);
makePackageWrapper vendor environment (pkg.override args);
}; };
wrappers = { wrappers = {
@ -256,49 +289,64 @@ in {
nvidia = makePackageWrapper "Nvidia" { }; nvidia = makePackageWrapper "Nvidia" { };
nvidiaPrime = makePackageWrapper "Nvidia" nvOffloadEnv; nvidiaPrime = makePackageWrapper "Nvidia" nvOffloadEnv;
}; };
in { in
{
lib.nixGL.wrap = wrappers.${cfg.defaultWrapper}; lib.nixGL.wrap = wrappers.${cfg.defaultWrapper};
lib.nixGL.wrapOffload = wrappers.${cfg.offloadWrapper}; lib.nixGL.wrapOffload = wrappers.${cfg.offloadWrapper};
lib.nixGL.wrappers = wrappers; lib.nixGL.wrappers = wrappers;
home.packages = let home.packages =
let
wantsPrimeWrapper = (!isNull cfg.prime.installScript); wantsPrimeWrapper = (!isNull cfg.prime.installScript);
wantsWrapper = wrapper: wantsWrapper =
(!isNull cfg.packages) && (!isNull cfg.installScripts) wrapper:
(!isNull cfg.packages)
&& (!isNull cfg.installScripts)
&& (builtins.elem wrapper cfg.installScripts); && (builtins.elem wrapper cfg.installScripts);
envVarsAsScript = environment: envVarsAsScript =
lib.concatStringsSep "\n" environment:
(lib.attrsets.mapAttrsToList (var: val: "export ${var}=${val}") lib.concatStringsSep "\n" (
environment); lib.attrsets.mapAttrsToList (var: val: "export ${var}=${val}") environment
in [ );
(lib.mkIf wantsPrimeWrapper (pkgs.writeShellScriptBin "prime-offload" '' in
${if cfg.prime.installScript == "mesa" then [
(lib.mkIf wantsPrimeWrapper (
pkgs.writeShellScriptBin "prime-offload" ''
${
if cfg.prime.installScript == "mesa" then
(envVarsAsScript mesaOffloadEnv) (envVarsAsScript mesaOffloadEnv)
else else
(envVarsAsScript nvOffloadEnv)} (envVarsAsScript nvOffloadEnv)
}
exec "$@" exec "$@"
'')) ''
))
(lib.mkIf (wantsWrapper "mesa") (pkgs.writeShellScriptBin "nixGLMesa" '' (lib.mkIf (wantsWrapper "mesa") (
pkgs.writeShellScriptBin "nixGLMesa" ''
exec ${getWrapperExe "Intel"} "$@" exec ${getWrapperExe "Intel"} "$@"
'')) ''
))
(lib.mkIf (wantsWrapper "mesaPrime") (lib.mkIf (wantsWrapper "mesaPrime") (
(pkgs.writeShellScriptBin "nixGLMesaPrime" '' pkgs.writeShellScriptBin "nixGLMesaPrime" ''
${envVarsAsScript mesaOffloadEnv} ${envVarsAsScript mesaOffloadEnv}
exec ${getWrapperExe "Intel"} "$@" exec ${getWrapperExe "Intel"} "$@"
'')) ''
))
(lib.mkIf (wantsWrapper "nvidia") (lib.mkIf (wantsWrapper "nvidia") (
(pkgs.writeShellScriptBin "nixGLNvidia" '' pkgs.writeShellScriptBin "nixGLNvidia" ''
exec ${getWrapperExe "Nvidia"} "$@" exec ${getWrapperExe "Nvidia"} "$@"
'')) ''
))
(lib.mkIf (wantsWrapper "nvidia") (lib.mkIf (wantsWrapper "nvidia") (
(pkgs.writeShellScriptBin "nixGLNvidiaPrime" '' pkgs.writeShellScriptBin "nixGLNvidiaPrime" ''
${envVarsAsScript nvOffloadEnv} ${envVarsAsScript nvOffloadEnv}
exec ${getWrapperExe "Nvidia"} "$@" exec ${getWrapperExe "Nvidia"} "$@"
'')) ''
))
]; ];
}; };
} }

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
@ -11,16 +16,22 @@ let
optCall = f: x: if builtins.isFunction f then f x else f; optCall = f: x: if builtins.isFunction f then f x else f;
# Copied from nixpkgs.nix. # Copied from nixpkgs.nix.
mergeConfig = lhs_: rhs_: mergeConfig =
lhs_: rhs_:
let let
lhs = optCall lhs_ { inherit pkgs; }; lhs = optCall lhs_ { inherit pkgs; };
rhs = optCall rhs_ { inherit pkgs; }; rhs = optCall rhs_ { inherit pkgs; };
in lhs // rhs // lib.optionalAttrs (lhs ? packageOverrides) { in
packageOverrides = pkgs: lhs
optCall lhs.packageOverrides pkgs // rhs
// optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs; // lib.optionalAttrs (lhs ? packageOverrides) {
} // lib.optionalAttrs (lhs ? perlPackageOverrides) { packageOverrides =
perlPackageOverrides = pkgs: pkgs:
optCall lhs.packageOverrides pkgs // optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs;
}
// lib.optionalAttrs (lhs ? perlPackageOverrides) {
perlPackageOverrides =
pkgs:
optCall lhs.perlPackageOverrides pkgs optCall lhs.perlPackageOverrides pkgs
// optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs; // optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs;
}; };
@ -29,9 +40,12 @@ let
configType = lib.mkOptionType { configType = lib.mkOptionType {
name = "nixpkgs-config"; name = "nixpkgs-config";
description = "nixpkgs config"; description = "nixpkgs config";
check = x: check =
let traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false; x:
in traceXIfNot isConfig; let
traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false;
in
traceXIfNot isConfig;
merge = args: lib.fold (def: mergeConfig def.value) { }; merge = args: lib.fold (def: mergeConfig def.value) { };
}; };
@ -43,7 +57,8 @@ let
merge = lib.mergeOneOption; merge = lib.mergeOneOption;
}; };
in { in
{
meta.maintainers = with lib.maintainers; [ thiagokokada ]; meta.maintainers = with lib.maintainers; [ thiagokokada ];
options.nixpkgs = { options.nixpkgs = {

View file

@ -1,6 +1,12 @@
# Adapted from Nixpkgs. # Adapted from Nixpkgs.
{ config, lib, pkgs, pkgsPath, ... }: {
config,
lib,
pkgs,
pkgsPath,
...
}:
let let
@ -8,16 +14,22 @@ let
optCall = f: x: if builtins.isFunction f then f x else f; optCall = f: x: if builtins.isFunction f then f x else f;
mergeConfig = lhs_: rhs_: mergeConfig =
lhs_: rhs_:
let let
lhs = optCall lhs_ { inherit pkgs; }; lhs = optCall lhs_ { inherit pkgs; };
rhs = optCall rhs_ { inherit pkgs; }; rhs = optCall rhs_ { inherit pkgs; };
in lhs // rhs // lib.optionalAttrs (lhs ? packageOverrides) { in
packageOverrides = pkgs: lhs
optCall lhs.packageOverrides pkgs // rhs
// optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs; // lib.optionalAttrs (lhs ? packageOverrides) {
} // lib.optionalAttrs (lhs ? perlPackageOverrides) { packageOverrides =
perlPackageOverrides = pkgs: pkgs:
optCall lhs.packageOverrides pkgs // optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs;
}
// lib.optionalAttrs (lhs ? perlPackageOverrides) {
perlPackageOverrides =
pkgs:
optCall lhs.perlPackageOverrides pkgs optCall lhs.perlPackageOverrides pkgs
// optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs; // optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs;
}; };
@ -25,9 +37,12 @@ let
configType = lib.mkOptionType { configType = lib.mkOptionType {
name = "nixpkgs-config"; name = "nixpkgs-config";
description = "nixpkgs config"; description = "nixpkgs config";
check = x: check =
let traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false; x:
in traceXIfNot isConfig; let
traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false;
in
traceXIfNot isConfig;
merge = args: lib.fold (def: mergeConfig def.value) { }; merge = args: lib.fold (def: mergeConfig def.value) { };
}; };
@ -40,11 +55,14 @@ let
_pkgs = import pkgsPath (lib.filterAttrs (n: v: v != null) config.nixpkgs); _pkgs = import pkgsPath (lib.filterAttrs (n: v: v != null) config.nixpkgs);
in { in
{
options.nixpkgs = { options.nixpkgs = {
config = lib.mkOption { config = lib.mkOption {
default = null; default = null;
example = { allowBroken = true; }; example = {
allowBroken = true;
};
type = lib.types.nullOr configType; type = lib.types.nullOr configType;
description = '' description = ''
The configuration of the Nix Packages collection. (For The configuration of the Nix Packages collection. (For
@ -123,10 +141,7 @@ in {
# `_pkgs`, see https://github.com/nix-community/home-manager/pull/993 # `_pkgs`, see https://github.com/nix-community/home-manager/pull/993
pkgs = lib.mkOverride lib.modules.defaultOverridePriority _pkgs; pkgs = lib.mkOverride lib.modules.defaultOverridePriority _pkgs;
pkgs_i686 = pkgs_i686 =
if _pkgs.stdenv.isLinux && _pkgs.stdenv.hostPlatform.isx86 then if _pkgs.stdenv.isLinux && _pkgs.stdenv.hostPlatform.isx86 then _pkgs.pkgsi686Linux else { };
_pkgs.pkgsi686Linux
else
{ };
}; };
}; };
} }

View file

@ -1,18 +1,25 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.xsession.numlock; cfg = config.xsession.numlock;
in { in
{
meta.maintainers = [ lib.maintainers.evanjs ]; meta.maintainers = [ lib.maintainers.evanjs ];
options = { xsession.numlock.enable = lib.mkEnableOption "Num Lock"; }; options = {
xsession.numlock.enable = lib.mkEnableOption "Num Lock";
};
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
assertions = [ assertions = [
(lib.hm.assertions.assertPlatform "xsession.numlock" pkgs (lib.hm.assertions.assertPlatform "xsession.numlock" pkgs lib.platforms.linux)
lib.platforms.linux)
]; ];
systemd.user.services.numlockx = { systemd.user.services.numlockx = {
@ -28,7 +35,9 @@ in {
ExecStart = "${pkgs.numlockx}/bin/numlockx"; ExecStart = "${pkgs.numlockx}/bin/numlockx";
}; };
Install = { WantedBy = [ "graphical-session.target" ]; }; Install = {
WantedBy = [ "graphical-session.target" ];
};
}; };
}; };
} }

View file

@ -4,14 +4,20 @@ let
cfg = config.pam; cfg = config.pam;
in { in
meta.maintainers = with lib.maintainers; [ rycee veehaitch ]; {
meta.maintainers = with lib.maintainers; [
rycee
veehaitch
];
options = { options = {
pam.sessionVariables = lib.mkOption { pam.sessionVariables = lib.mkOption {
default = { }; default = { };
type = lib.types.attrs; type = lib.types.attrs;
example = { EDITOR = "vim"; }; example = {
EDITOR = "vim";
};
description = '' description = ''
Environment variables that will be set for the PAM session. Environment variables that will be set for the PAM session.
The variable values must be as described in The variable values must be as described in
@ -24,13 +30,15 @@ in {
pam.yubico.authorizedYubiKeys = { pam.yubico.authorizedYubiKeys = {
ids = lib.mkOption { ids = lib.mkOption {
type = with lib.types; type =
with lib.types;
let let
yubiKeyId = addCheck str (s: lib.stringLength s == 12) // { yubiKeyId = addCheck str (s: lib.stringLength s == 12) // {
name = "yubiKeyId"; name = "yubiKeyId";
description = "string of length 12"; description = "string of length 12";
}; };
in listOf yubiKeyId; in
listOf yubiKeyId;
default = [ ]; default = [ ];
description = '' description = ''
List of authorized YubiKey token IDs. Refer to List of authorized YubiKey token IDs. Refer to
@ -52,15 +60,17 @@ in {
config = lib.mkMerge [ config = lib.mkMerge [
(lib.mkIf (cfg.sessionVariables != { }) { (lib.mkIf (cfg.sessionVariables != { }) {
home.file.".pam_environment".text = lib.concatStringsSep "\n" home.file.".pam_environment".text =
(lib.mapAttrsToList (n: v: ''${n} OVERRIDE="${toString v}"'') lib.concatStringsSep "\n" (
cfg.sessionVariables) + "\n"; lib.mapAttrsToList (n: v: ''${n} OVERRIDE="${toString v}"'') cfg.sessionVariables
)
+ "\n";
}) })
(lib.mkIf (cfg.yubico.authorizedYubiKeys.ids != [ ]) { (lib.mkIf (cfg.yubico.authorizedYubiKeys.ids != [ ]) {
home.file.${cfg.yubico.authorizedYubiKeys.path}.text = home.file.${cfg.yubico.authorizedYubiKeys.path}.text = lib.concatStringsSep ":" (
lib.concatStringsSep ":" [ config.home.username ] ++ cfg.yubico.authorizedYubiKeys.ids
([ config.home.username ] ++ cfg.yubico.authorizedYubiKeys.ids); );
}) })
]; ];
} }

View file

@ -1,13 +1,27 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.qt; cfg = config.qt;
# Map platform names to their packages. # Map platform names to their packages.
platformPackages = with pkgs; { platformPackages = with pkgs; {
gnome = [ qgnomeplatform qgnomeplatform-qt6 ]; gnome = [
adwaita = [ qadwaitadecorations qadwaitadecorations-qt6 ]; qgnomeplatform
gtk = [ libsForQt5.qtstyleplugins qt6Packages.qt6gtk2 ]; qgnomeplatform-qt6
];
adwaita = [
qadwaitadecorations
qadwaitadecorations-qt6
];
gtk = [
libsForQt5.qtstyleplugins
qt6Packages.qt6gtk2
];
kde = [ kde = [
libsForQt5.kio libsForQt5.kio
libsForQt5.plasma-integration libsForQt5.plasma-integration
@ -18,8 +32,14 @@ let
kdePackages.plasma-integration kdePackages.plasma-integration
kdePackages.systemsettings kdePackages.systemsettings
]; ];
lxqt = [ lxqt.lxqt-qtplugin lxqt.lxqt-config ]; lxqt = [
qtct = [ libsForQt5.qt5ct qt6Packages.qt6ct ]; lxqt.lxqt-qtplugin
lxqt.lxqt-config
];
qtct = [
libsForQt5.qt5ct
qt6Packages.qt6ct
];
}; };
# Maps style names to their QT_QPA_PLATFORMTHEME, if necessary. # Maps style names to their QT_QPA_PLATFORMTHEME, if necessary.
@ -34,39 +54,58 @@ let
bb10bright = libsForQt5.qtstyleplugins; bb10bright = libsForQt5.qtstyleplugins;
bb10dark = libsForQt5.qtstyleplugins; bb10dark = libsForQt5.qtstyleplugins;
cleanlooks = libsForQt5.qtstyleplugins; cleanlooks = libsForQt5.qtstyleplugins;
gtk2 = [ libsForQt5.qtstyleplugins qt6Packages.qt6gtk2 ]; gtk2 = [
libsForQt5.qtstyleplugins
qt6Packages.qt6gtk2
];
motif = libsForQt5.qtstyleplugins; motif = libsForQt5.qtstyleplugins;
cde = libsForQt5.qtstyleplugins; cde = libsForQt5.qtstyleplugins;
plastique = libsForQt5.qtstyleplugins; plastique = libsForQt5.qtstyleplugins;
adwaita = [ adwaita-qt adwaita-qt6 ]; adwaita = [
adwaita-dark = [ adwaita-qt adwaita-qt6 ]; adwaita-qt
adwaita-highcontrast = [ adwaita-qt adwaita-qt6 ]; adwaita-qt6
adwaita-highcontrastinverse = [ adwaita-qt adwaita-qt6 ]; ];
adwaita-dark = [
adwaita-qt
adwaita-qt6
];
adwaita-highcontrast = [
adwaita-qt
adwaita-qt6
];
adwaita-highcontrastinverse = [
adwaita-qt
adwaita-qt6
];
breeze = libsForQt5.breeze-qt5; breeze = libsForQt5.breeze-qt5;
kvantum = kvantum = [
[ libsForQt5.qtstyleplugin-kvantum qt6Packages.qtstyleplugin-kvantum ]; libsForQt5.qtstyleplugin-kvantum
qt6Packages.qtstyleplugin-kvantum
];
}; };
in { in
meta.maintainers = with lib.maintainers; [ rycee thiagokokada ]; {
meta.maintainers = with lib.maintainers; [
rycee
thiagokokada
];
imports = [ imports = [
(lib.mkChangedOptionModule [ "qt" "useGtkTheme" ] [ "qt" "platformTheme" ] (lib.mkChangedOptionModule [ "qt" "useGtkTheme" ] [ "qt" "platformTheme" ] (
(config: config: if lib.getAttrFromPath [ "qt" "useGtkTheme" ] config then "gtk" else null
if lib.getAttrFromPath [ "qt" "useGtkTheme" ] config then ))
"gtk"
else
null))
]; ];
options = { options = {
qt = { qt = {
enable = lib.mkEnableOption "Qt 5 and 6 configuration"; enable = lib.mkEnableOption "Qt 5 and 6 configuration";
platformTheme = let platformTheme =
let
newOption = { newOption = {
name = lib.mkOption { name = lib.mkOption {
type = with lib.types; nullOr str; type = with lib.types; nullOr str;
@ -77,16 +116,46 @@ in {
"qgnomeplatform-qt6" "qgnomeplatform-qt6"
"qadwaitadecorations" "qadwaitadecorations"
"qadwaitadecorations-qt6" "qadwaitadecorations-qt6"
[ "libsForQt5" "plasma-integration" ] [
[ "libsForQt5" "qt5ct" ] "libsForQt5"
[ "libsForQt5" "qtstyleplugins" ] "plasma-integration"
[ "libsForQt5" "systemsettings" ] ]
[ "kdePackages" "plasma-integration" ] [
[ "kdePackages" "systemsettings" ] "libsForQt5"
[ "lxqt" "lxqt-config" ] "qt5ct"
[ "lxqt" "lxqt-qtplugin" ] ]
[ "qt6Packages" "qt6ct" ] [
[ "qt6Packages" "qt6gtk2" ] "libsForQt5"
"qtstyleplugins"
]
[
"libsForQt5"
"systemsettings"
]
[
"kdePackages"
"plasma-integration"
]
[
"kdePackages"
"systemsettings"
]
[
"lxqt"
"lxqt-config"
]
[
"lxqt"
"lxqt-qtplugin"
]
[
"qt6Packages"
"qt6ct"
]
[
"qt6Packages"
"qt6gtk2"
]
]; ];
description = '' description = ''
Platform theme to use for Qt applications. Platform theme to use for Qt applications.
@ -131,8 +200,7 @@ in {
package = lib.mkOption { package = lib.mkOption {
type = with lib.types; nullOr (either package (listOf package)); type = with lib.types; nullOr (either package (listOf package));
default = null; default = null;
example = example = lib.literalExpression "[pkgs.adwaita-qt pkgs.adwaita-qt6]";
lib.literalExpression "[pkgs.adwaita-qt pkgs.adwaita-qt6]";
description = '' description = ''
Theme package to be used in Qt5/Qt6 applications. Theme package to be used in Qt5/Qt6 applications.
Auto-detected from {option}`qt.platformTheme.name` if possible. Auto-detected from {option}`qt.platformTheme.name` if possible.
@ -140,11 +208,22 @@ in {
''; '';
}; };
}; };
in lib.mkOption { in
type = with lib.types; lib.mkOption {
nullOr (either type =
(enum [ "gtk" "gtk3" "gnome" "adwaita" "lxqt" "qtct" "kde" "kde6" ]) with lib.types;
(lib.types.submodule { options = newOption; })); nullOr (
either (enum [
"gtk"
"gtk3"
"gnome"
"adwaita"
"lxqt"
"qtct"
"kde"
"kde6"
]) (lib.types.submodule { options = newOption; })
);
default = null; default = null;
description = '' description = ''
Deprecated. Use {option}`qt.platformTheme.name` instead. Deprecated. Use {option}`qt.platformTheme.name` instead.
@ -158,11 +237,26 @@ in {
relatedPackages = [ relatedPackages = [
"adwaita-qt" "adwaita-qt"
"adwaita-qt6" "adwaita-qt6"
[ "libsForQt5" "breeze-qt5" ] [
[ "libsForQt5" "qtstyleplugin-kvantum" ] "libsForQt5"
[ "libsForQt5" "qtstyleplugins" ] "breeze-qt5"
[ "qt6Packages" "qt6gtk2" ] ]
[ "qt6Packages" "qtstyleplugin-kvantum" ] [
"libsForQt5"
"qtstyleplugin-kvantum"
]
[
"libsForQt5"
"qtstyleplugins"
]
[
"qt6Packages"
"qt6gtk2"
]
[
"qt6Packages"
"qtstyleplugin-kvantum"
]
]; ];
description = '' description = ''
Style to use for Qt5/Qt6 applications. Case-insensitive. Style to use for Qt5/Qt6 applications. Case-insensitive.
@ -201,16 +295,23 @@ in {
}; };
}; };
config = let config =
platformTheme = if (builtins.isString cfg.platformTheme) then { let
platformTheme =
if (builtins.isString cfg.platformTheme) then
{
option = "qt.platformTheme"; option = "qt.platformTheme";
name = cfg.platformTheme; name = cfg.platformTheme;
package = null; package = null;
} else if cfg.platformTheme == null then { }
else if cfg.platformTheme == null then
{
option = null; option = null;
name = null; name = null;
package = null; package = null;
} else { }
else
{
option = "qt.platformTheme.name"; option = "qt.platformTheme.name";
name = cfg.platformTheme.name; name = cfg.platformTheme.name;
package = cfg.platformTheme.package; package = cfg.platformTheme.package;
@ -218,41 +319,51 @@ in {
# Necessary because home.sessionVariables doesn't support mkIf # Necessary because home.sessionVariables doesn't support mkIf
envVars = lib.filterAttrs (n: v: v != null) { envVars = lib.filterAttrs (n: v: v != null) {
QT_QPA_PLATFORMTHEME = if (platformTheme.name != null) then QT_QPA_PLATFORMTHEME =
if (platformTheme.name != null) then
styleNames.${platformTheme.name} or platformTheme.name styleNames.${platformTheme.name} or platformTheme.name
else else
null; null;
QT_STYLE_OVERRIDE = cfg.style.name; QT_STYLE_OVERRIDE = cfg.style.name;
}; };
envVarsExtra = let envVarsExtra =
let
inherit (config.home) profileDirectory; inherit (config.home) profileDirectory;
qtVersions = with pkgs; [ qt5 qt6 ]; qtVersions = with pkgs; [
makeQtPath = prefix: qt5
(map (qt: "${profileDirectory}/${qt.qtbase.${prefix}}") qtVersions); qt6
in { ];
makeQtPath = prefix: (map (qt: "${profileDirectory}/${qt.qtbase.${prefix}}") qtVersions);
in
{
QT_PLUGIN_PATH = makeQtPath "qtPluginPrefix"; QT_PLUGIN_PATH = makeQtPath "qtPluginPrefix";
QML2_IMPORT_PATH = makeQtPath "qtQmlPrefix"; QML2_IMPORT_PATH = makeQtPath "qtQmlPrefix";
}; };
in lib.mkIf cfg.enable { in
assertions = [{ lib.mkIf cfg.enable {
assertion = platformTheme.name == "gnome" -> cfg.style.name != null assertions = [
&& cfg.style.package != null; {
assertion = platformTheme.name == "gnome" -> cfg.style.name != null && cfg.style.package != null;
message = '' message = ''
`qt.platformTheme.name` "gnome" must have `qt.style` set to a theme that `qt.platformTheme.name` "gnome" must have `qt.style` set to a theme that
supports both Qt and Gtk, for example "adwaita", "adwaita-dark", or "breeze". supports both Qt and Gtk, for example "adwaita", "adwaita-dark", or "breeze".
''; '';
}]; }
];
warnings = (lib.lists.optional (platformTheme.option == "qt.platformTheme") warnings =
"The option `qt.platformTheme` has been renamed to `qt.platformTheme.name`.") (lib.lists.optional (
++ (lib.lists.optional platformTheme.option == "qt.platformTheme"
(platformTheme.name == "gnome" && platformTheme.package == null) ) "The option `qt.platformTheme` has been renamed to `qt.platformTheme.name`.")
"The value `gnome` for option `${platformTheme.option}` is deprecated. Use `adwaita` instead."); ++ (lib.lists.optional (
platformTheme.name == "gnome" && platformTheme.package == null
) "The value `gnome` for option `${platformTheme.option}` is deprecated. Use `adwaita` instead.");
qt.style.package = lib.mkIf (cfg.style.name != null) qt.style.package = lib.mkIf (cfg.style.name != null) (
(lib.mkDefault (stylePackages.${lib.toLower cfg.style.name} or null)); lib.mkDefault (stylePackages.${lib.toLower cfg.style.name} or null)
);
home = { home = {
sessionVariables = envVars; sessionVariables = envVars;
@ -265,15 +376,21 @@ in {
QML2_IMPORT_PATH = lib.concatStringsSep ":" envVarsExtra.QML2_IMPORT_PATH; QML2_IMPORT_PATH = lib.concatStringsSep ":" envVarsExtra.QML2_IMPORT_PATH;
}; };
home.packages = (lib.findFirst (x: x != [ ]) [ ] [ home.packages =
(lib.optionals (platformTheme.package != null) (lib.findFirst (x: x != [ ])
(lib.toList platformTheme.package)) [ ]
(lib.optionals (platformTheme.name != null) [
platformPackages.${platformTheme.name} or [ ]) (lib.optionals (platformTheme.package != null) (lib.toList platformTheme.package))
]) ++ (lib.optionals (cfg.style.package != null) (lib.optionals (platformTheme.name != null) platformPackages.${platformTheme.name} or [ ])
(lib.toList cfg.style.package)); ]
)
++ (lib.optionals (cfg.style.package != null) (lib.toList cfg.style.package));
xsession.importedVariables = [ "QT_PLUGIN_PATH" "QML2_IMPORT_PATH" ] xsession.importedVariables =
[
"QT_PLUGIN_PATH"
"QML2_IMPORT_PATH"
]
++ lib.optionals (platformTheme.name != null) [ "QT_QPA_PLATFORMTHEME" ] ++ lib.optionals (platformTheme.name != null) [ "QT_QPA_PLATFORMTHEME" ]
++ lib.optionals (cfg.style.name != null) [ "QT_STYLE_OVERRIDE" ]; ++ lib.optionals (cfg.style.name != null) [ "QT_STYLE_OVERRIDE" ];
}; };

View file

@ -1,17 +1,33 @@
{ config, pkgs, lib, ... }: {
config,
pkgs,
lib,
...
}:
let let
cfg = config.qt.kde.settings; cfg = config.qt.kde.settings;
in { in
{
options.qt.kde.settings = lib.mkOption { options.qt.kde.settings = lib.mkOption {
type = with lib.types; type =
with lib.types;
let let
valueType = valueType =
nullOr (oneOf [ bool int float str path (attrsOf valueType) ]) // { nullOr (oneOf [
bool
int
float
str
path
(attrsOf valueType)
])
// {
description = "KDE option value"; description = "KDE option value";
}; };
in attrsOf valueType; in
attrsOf valueType;
default = { }; default = { };
example = { example = {
powermanagementprofilesrc.AC.HandleButtonEvents.lidAction = 32; powermanagementprofilesrc.AC.HandleButtonEvents.lidAction = 32;
@ -38,28 +54,32 @@ in {
config = lib.mkIf (cfg != { }) { config = lib.mkIf (cfg != { }) {
home.activation.kconfig = lib.hm.dag.entryAfter [ "writeBoundary" ] '' home.activation.kconfig = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
${let ${
let
inherit (config.xdg) configHome; inherit (config.xdg) configHome;
toValue = v: toValue =
let t = builtins.typeOf v; v:
in if v == null then let
t = builtins.typeOf v;
in
if v == null then
"--delete" "--delete"
else if t == "bool" then else if t == "bool" then
"--type bool ${builtins.toJSON v}" "--type bool ${builtins.toJSON v}"
else else
lib.escapeShellArg (toString v); lib.escapeShellArg (toString v);
toLine = file: path: value: toLine =
file: path: value:
if builtins.isAttrs value then if builtins.isAttrs value then
lib.mapAttrsToList lib.mapAttrsToList (group: value: toLine file (path ++ [ group ]) value) value
(group: value: toLine file (path ++ [ group ]) value) value
else else
"run ${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file '${configHome}/${file}' ${ "run ${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file '${configHome}/${file}' ${
lib.concatMapStringsSep " " (x: "--group ${x}") lib.concatMapStringsSep " " (x: "--group ${x}") (lib.lists.init path)
(lib.lists.init path)
} --key '${lib.lists.last path}' ${toValue value}"; } --key '${lib.lists.last path}' ${toValue value}";
lines = lib.flatten lines = lib.flatten (lib.mapAttrsToList (file: attrs: toLine file [ ] attrs) cfg);
(lib.mapAttrsToList (file: attrs: toLine file [ ] attrs) cfg); in
in builtins.concatStringsSep "\n" lines} builtins.concatStringsSep "\n" lines
}
# TODO: some way to only call the dbus calls needed # TODO: some way to only call the dbus calls needed
run ${pkgs.kdePackages.qttools}/bin/qdbus org.kde.KWin /KWin reconfigure || echo "KWin reconfigure failed" run ${pkgs.kdePackages.qttools}/bin/qdbus org.kde.KWin /KWin reconfigure || echo "KWin reconfigure failed"

View file

@ -1,16 +1,24 @@
{ config, name, extendModules, lib, ... }: {
config,
name,
extendModules,
lib,
...
}:
{ {
imports = imports = [ (lib.mkRenamedOptionModule [ "specialization" ] [ "specialisation" ]) ];
[ (lib.mkRenamedOptionModule [ "specialization" ] [ "specialisation" ]) ];
options.specialisation = lib.mkOption { options.specialisation = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule { type = lib.types.attrsOf (
lib.types.submodule {
options = { options = {
configuration = lib.mkOption { configuration = lib.mkOption {
type = let type =
let
extended = extendModules { extended = extendModules {
modules = [{ modules = [
{
# Prevent infinite recursion # Prevent infinite recursion
specialisation = lib.mkOverride 0 { }; specialisation = lib.mkOverride 0 { };
@ -20,9 +28,11 @@
# option. Thus we need to explicitly wire the former into the module arguments. # option. Thus we need to explicitly wire the former into the module arguments.
# See discussion at https://github.com/nix-community/home-manager/issues/3716 # See discussion at https://github.com/nix-community/home-manager/issues/3716
_module.args.name = lib.mkForce name; _module.args.name = lib.mkForce name;
}]; }
];
}; };
in extended.type; in
extended.type;
default = { }; default = { };
visible = "shallow"; visible = "shallow";
description = '' description = ''
@ -30,7 +40,8 @@
''; '';
}; };
}; };
}); }
);
default = { }; default = { };
description = '' description = ''
A set of named specialized configurations. These can be used to extend A set of named specialized configurations. These can be used to extend
@ -71,18 +82,21 @@
config = lib.mkIf (config.specialisation != { }) { config = lib.mkIf (config.specialisation != { }) {
assertions = map (n: { assertions = map (n: {
assertion = !lib.hasInfix "/" n; assertion = !lib.hasInfix "/" n;
message = message = "<name> in specialisation.<name> cannot contain a forward slash.";
"<name> in specialisation.<name> cannot contain a forward slash.";
}) (lib.attrNames config.specialisation); }) (lib.attrNames config.specialisation);
home.extraBuilderCommands = let home.extraBuilderCommands =
link = n: v: let
let pkg = v.configuration.home.activationPackage; link =
in "ln -s ${pkg} $out/specialisation/${lib.escapeShellArg n}"; n: v:
in '' let
pkg = v.configuration.home.activationPackage;
in
"ln -s ${pkg} $out/specialisation/${lib.escapeShellArg n}";
in
''
mkdir $out/specialisation mkdir $out/specialisation
${lib.concatStringsSep "\n" ${lib.concatStringsSep "\n" (lib.mapAttrsToList link config.specialisation)}
(lib.mapAttrsToList link config.specialisation)}
''; '';
}; };
} }

View file

@ -1,10 +1,16 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.systemd.user.tmpfiles; cfg = config.systemd.user.tmpfiles;
in { in
{
meta.maintainers = [ lib.maintainers.dawidsowa ]; meta.maintainers = [ lib.maintainers.dawidsowa ];
options.systemd.user.tmpfiles.rules = lib.mkOption { options.systemd.user.tmpfiles.rules = lib.mkOption {
@ -21,8 +27,7 @@ in {
config = lib.mkIf (cfg.rules != [ ]) { config = lib.mkIf (cfg.rules != [ ]) {
assertions = [ assertions = [
(lib.hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs (lib.hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs lib.platforms.linux)
lib.platforms.linux)
]; ];
xdg.configFile = { xdg.configFile = {

View file

@ -4,7 +4,8 @@ let
inherit (lib) mkIf mkOption types; inherit (lib) mkIf mkOption types;
in { in
{
options.uninstall = mkOption { options.uninstall = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@ -26,8 +27,7 @@ in {
manual.manpages.enable = lib.mkForce false; manual.manpages.enable = lib.mkForce false;
news.display = lib.mkForce "silent"; news.display = lib.mkForce "silent";
home.activation.uninstall = home.activation.uninstall = lib.hm.dag.entryAfter [ "installPackages" "linkGeneration" ] ''
lib.hm.dag.entryAfter [ "installPackages" "linkGeneration" ] ''
nixProfileRemove home-manager-path nixProfileRemove home-manager-path
if [[ -e $hmDataPath ]]; then if [[ -e $hmDataPath ]]; then

View file

@ -5,7 +5,8 @@ let
releaseInfo = lib.importJSON ../../release.json; releaseInfo = lib.importJSON ../../release.json;
in { in
{
options = { options = {
home.stateVersion = lib.mkOption { home.stateVersion = lib.mkOption {
type = types.enum [ type = types.enum [
@ -44,11 +45,12 @@ in {
internal = true; internal = true;
readOnly = true; readOnly = true;
type = types.str; type = types.str;
default = let default =
let
inherit (config.home.version) release revision; inherit (config.home.version) release revision;
suffix = lib.optionalString (revision != null) suffix = lib.optionalString (revision != null) "+${lib.substring 0 8 revision}";
"+${lib.substring 0 8 revision}"; in
in "${release}${suffix}"; "${release}${suffix}";
example = "22.11+213a0629"; example = "22.11+213a0629";
description = "The full Home Manager version."; description = "The full Home Manager version.";
}; };
@ -76,11 +78,11 @@ in {
revision = lib.mkOption { revision = lib.mkOption {
internal = true; internal = true;
type = types.nullOr types.str; type = types.nullOr types.str;
default = let gitRepo = "${toString ./../..}/.git"; default =
in if lib.pathIsGitRepo gitRepo then let
lib.commitIdFromGitRepo gitRepo gitRepo = "${toString ./../..}/.git";
else in
null; if lib.pathIsGitRepo gitRepo then lib.commitIdFromGitRepo gitRepo else null;
description = '' description = ''
The Git revision from which this Home Manager configuration was built. The Git revision from which this Home Manager configuration was built.
''; '';

View file

@ -1,15 +1,22 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
{ {
meta.maintainers = [ lib.maintainers.rycee ]; meta.maintainers = [ lib.maintainers.rycee ];
options.programs = let options.programs =
let
description = '' description = ''
Whether to enable integration with terminals using the VTE Whether to enable integration with terminals using the VTE
library. This will let the terminal track the current working library. This will let the terminal track the current working
directory. directory.
''; '';
in { in
{
bash.enableVteIntegration = lib.mkEnableOption "" // { bash.enableVteIntegration = lib.mkEnableOption "" // {
inherit description; inherit description;
}; };

View file

@ -1,7 +1,23 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (builtins) baseNameOf listToAttrs map unsafeDiscardStringContext; inherit (builtins)
inherit (lib) literalExpression mkEnableOption mkIf mkOption types; baseNameOf
listToAttrs
map
unsafeDiscardStringContext
;
inherit (lib)
literalExpression
mkEnableOption
mkIf
mkOption
types
;
cfg = config.xdg.autostart; cfg = config.xdg.autostart;
@ -10,7 +26,8 @@ let
${lib.concatMapStringsSep "\n" (e: "ln -s ${e} $out") cfg.entries} ${lib.concatMapStringsSep "\n" (e: "ln -s ${e} $out") cfg.entries}
''; '';
in { in
{
meta.maintainers = with lib.maintainers; [ Scrumplex ]; meta.maintainers = with lib.maintainers; [ Scrumplex ];
options.xdg.autostart = { options.xdg.autostart = {

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) literalExpression mkOption types; inherit (lib) literalExpression mkOption types;
@ -6,9 +11,9 @@ let
desktopEntry = { desktopEntry = {
imports = [ imports = [
(lib.mkRemovedOptionModule [ "extraConfig" ] (lib.mkRemovedOptionModule [ "extraConfig" ]
"The `extraConfig` option of `xdg.desktopEntries` has been removed following a change in Nixpkgs.") "The `extraConfig` option of `xdg.desktopEntries` has been removed following a change in Nixpkgs."
(lib.mkRemovedOptionModule [ "fileValidation" ] )
"Validation of the desktop file is always enabled.") (lib.mkRemovedOptionModule [ "fileValidation" ] "Validation of the desktop file is always enabled.")
]; ];
options = { options = {
# Since this module uses the nixpkgs/pkgs/build-support/make-desktopitem function, # Since this module uses the nixpkgs/pkgs/build-support/make-desktopitem function,
@ -28,7 +33,11 @@ let
type = mkOption { type = mkOption {
description = "The type of the desktop entry."; description = "The type of the desktop entry.";
default = "Application"; default = "Application";
type = types.enum [ "Application" "Link" "Directory" ]; type = types.enum [
"Application"
"Link"
"Directory"
];
}; };
exec = mkOption { exec = mkOption {
@ -73,8 +82,7 @@ let
}; };
categories = mkOption { categories = mkOption {
description = description = "Categories in which the entry should be shown in a menu.";
"Categories in which the entry should be shown in a menu.";
type = types.nullOr (types.listOf types.str); type = types.nullOr (types.listOf types.str);
default = null; default = null;
}; };
@ -122,7 +130,10 @@ let
}; };
actions = mkOption { actions = mkOption {
type = types.attrsOf (types.submodule ({ name, ... }: { type = types.attrsOf (
types.submodule (
{ name, ... }:
{
options.name = mkOption { options.name = mkOption {
type = types.str; type = types.str;
default = name; default = name;
@ -139,7 +150,9 @@ let
default = null; default = null;
description = "Icon to display in file manager, menus, etc."; description = "Icon to display in file manager, menus, etc.";
}; };
})); }
)
);
default = { }; default = { };
defaultText = literalExpression "{ }"; defaultText = literalExpression "{ }";
example = literalExpression '' example = literalExpression ''
@ -149,8 +162,7 @@ let
}; };
} }
''; '';
description = description = "The set of actions made available to application launchers.";
"The set of actions made available to application launchers.";
}; };
# Required for the assertions # Required for the assertions
@ -165,18 +177,29 @@ let
}; };
#passes config options to makeDesktopItem in expected format #passes config options to makeDesktopItem in expected format
makeFile = name: config: makeFile =
name: config:
pkgs.makeDesktopItem { pkgs.makeDesktopItem {
inherit name; inherit name;
inherit (config) inherit (config)
type exec icon comment terminal genericName startupNotify noDisplay type
prefersNonDefaultGPU actions; exec
icon
comment
terminal
genericName
startupNotify
noDisplay
prefersNonDefaultGPU
actions
;
desktopName = config.name; desktopName = config.name;
mimeTypes = lib.optionals (config.mimeType != null) config.mimeType; mimeTypes = lib.optionals (config.mimeType != null) config.mimeType;
categories = lib.optionals (config.categories != null) config.categories; categories = lib.optionals (config.categories != null) config.categories;
extraConfig = config.settings; extraConfig = config.settings;
}; };
in { in
{
meta.maintainers = [ lib.hm.maintainers.cwyc ]; meta.maintainers = [ lib.hm.maintainers.cwyc ];
options.xdg.desktopEntries = mkOption { options.xdg.desktopEntries = mkOption {
@ -205,14 +228,13 @@ in {
config = lib.mkIf (config.xdg.desktopEntries != { }) { config = lib.mkIf (config.xdg.desktopEntries != { }) {
assertions = [ assertions = [
(lib.hm.assertions.assertPlatform "xdg.desktopEntries" pkgs (lib.hm.assertions.assertPlatform "xdg.desktopEntries" pkgs lib.platforms.linux)
lib.platforms.linux) ] ++ lib.flatten (lib.catAttrs "assertions" (lib.attrValues config.xdg.desktopEntries));
] ++ lib.flatten
(lib.catAttrs "assertions" (lib.attrValues config.xdg.desktopEntries));
home.packages = home.packages = (
(map lib.hiPrio # we need hiPrio to override existing entries map lib.hiPrio # we need hiPrio to override existing entries
(lib.attrsets.mapAttrsToList makeFile config.xdg.desktopEntries)); (lib.attrsets.mapAttrsToList makeFile config.xdg.desktopEntries)
);
}; };
} }

View file

@ -1,14 +1,19 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkOption types; inherit (lib) mkOption types;
cfg = config.xdg.mimeApps; cfg = config.xdg.mimeApps;
strListOrSingleton = with types; strListOrSingleton = with types; coercedTo (either (listOf str) str) lib.toList (listOf str);
coercedTo (either (listOf str) str) lib.toList (listOf str);
in { in
{
meta.maintainers = with lib.maintainers; [ euxane ]; meta.maintainers = with lib.maintainers; [ euxane ];
options.xdg.mimeApps = { options.xdg.mimeApps = {
@ -44,7 +49,9 @@ in {
associations.removed = mkOption { associations.removed = mkOption {
type = types.attrsOf strListOrSingleton; type = types.attrsOf strListOrSingleton;
default = { }; default = { };
example = { "mimetype1" = "foo5.desktop"; }; example = {
"mimetype1" = "foo5.desktop";
};
description = '' description = ''
Removes associations of applications with mimetypes, as if the Removes associations of applications with mimetypes, as if the
.desktop file was *not* listing this .desktop file was *not* listing this
@ -75,19 +82,22 @@ in {
# Given a package that installs .desktop files in the usual location, # Given a package that installs .desktop files in the usual location,
# return a mapping from mime types to lists of desktop file names. This is # return a mapping from mime types to lists of desktop file names. This is
# suitable for use with `xdg.mimeApps.defaultApplications`. # suitable for use with `xdg.mimeApps.defaultApplications`.
lib.xdg.mimeAssociations = let lib.xdg.mimeAssociations =
processLines = str: let
lib.zipAttrs (lib.filter (e: e != null) processLines =
(map processLine (lib.splitString "\n" str))); str: lib.zipAttrs (lib.filter (e: e != null) (map processLine (lib.splitString "\n" str)));
processLine = str: processLine =
str:
let let
entry = lib.splitString ";" str; entry = lib.splitString ";" str;
k = lib.elemAt entry 0; k = lib.elemAt entry 0;
v = lib.elemAt entry 1; v = lib.elemAt entry 1;
in if lib.length entry == 2 then { ${k} = v; } else null; in
if lib.length entry == 2 then { ${k} = v; } else null;
associations = ps: associations =
ps:
pkgs.runCommand "mime-assoc" { inherit ps; } '' pkgs.runCommand "mime-assoc" { inherit ps; } ''
for p in $ps ; do for p in $ps ; do
for path in "$p"/share/applications/*.desktop ; do for path in "$p"/share/applications/*.desktop ; do
@ -96,22 +106,23 @@ in {
done done
done > "$out" done > "$out"
''; '';
in p: processLines (builtins.readFile (associations p)); in
p: processLines (builtins.readFile (associations p));
} }
(lib.mkIf cfg.enable { (lib.mkIf cfg.enable {
assertions = [ assertions = [
(lib.hm.assertions.assertPlatform "xdg.mimeApps" pkgs (lib.hm.assertions.assertPlatform "xdg.mimeApps" pkgs lib.platforms.linux)
lib.platforms.linux)
]; ];
# Deprecated but still used by some applications. # Deprecated but still used by some applications.
xdg.dataFile."applications/mimeapps.list".source = xdg.dataFile."applications/mimeapps.list".source = config.xdg.configFile."mimeapps.list".source;
config.xdg.configFile."mimeapps.list".source;
xdg.configFile."mimeapps.list".text = xdg.configFile."mimeapps.list".text =
let joinValues = lib.mapAttrs (n: lib.concatStringsSep ";"); let
in lib.generators.toINI { } { joinValues = lib.mapAttrs (n: lib.concatStringsSep ";");
in
lib.generators.toINI { } {
"Added Associations" = joinValues cfg.associations.added; "Added Associations" = joinValues cfg.associations.added;
"Removed Associations" = joinValues cfg.associations.removed; "Removed Associations" = joinValues cfg.associations.removed;
"Default Applications" = joinValues cfg.defaultApplications; "Default Applications" = joinValues cfg.defaultApplications;

View file

@ -1,19 +1,29 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.xdg.mime; cfg = config.xdg.mime;
inherit (lib) getExe getExe' mkOption types; inherit (lib)
getExe
getExe'
mkOption
types
;
in { in
{
options = { options = {
xdg.mime = { xdg.mime = {
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = pkgs.stdenv.hostPlatform.isLinux; default = pkgs.stdenv.hostPlatform.isLinux;
defaultText = lib.literalExpression defaultText = lib.literalExpression "true if host platform is Linux, false otherwise";
"true if host platform is Linux, false otherwise";
description = '' description = ''
Whether to install programs and files to support the Whether to install programs and files to support the
XDG Shared MIME-info specification and XDG MIME Applications XDG Shared MIME-info specification and XDG MIME Applications
@ -36,8 +46,7 @@ in {
type = types.package; type = types.package;
default = pkgs.desktop-file-utils; default = pkgs.desktop-file-utils;
defaultText = lib.literalExpression "pkgs.desktop-file-utils"; defaultText = lib.literalExpression "pkgs.desktop-file-utils";
description = description = "The package to use when running update-desktop-database.";
"The package to use when running update-desktop-database.";
}; };
}; };
}; };
@ -64,16 +73,14 @@ in {
XDG_DATA_DIRS=$out/share \ XDG_DATA_DIRS=$out/share \
PKGSYSTEM_ENABLE_FSYNC=0 \ PKGSYSTEM_ENABLE_FSYNC=0 \
${ ${
getExe getExe (cfg.sharedMimeInfoPackage.__spliced.buildHost or cfg.sharedMimeInfoPackage)
(cfg.sharedMimeInfoPackage.__spliced.buildHost or cfg.sharedMimeInfoPackage)
} -V $out/share/mime > /dev/null } -V $out/share/mime > /dev/null
fi fi
if [[ -w $out/share/applications ]]; then if [[ -w $out/share/applications ]]; then
${ ${
getExe' getExe' (cfg.desktopFileUtilsPackage.__spliced.buildHost or cfg.desktopFileUtilsPackage
(cfg.desktopFileUtilsPackage.__spliced.buildHost or cfg.desktopFileUtilsPackage) ) "update-desktop-database"
"update-desktop-database"
} $out/share/applications } $out/share/applications
fi fi
''; '';

View file

@ -1,14 +1,26 @@
{ config, pkgs, lib, ... }: {
config,
pkgs,
lib,
...
}:
let let
inherit (lib) mkIf mkMerge mkOption optional types; inherit (lib)
mkIf
mkMerge
mkOption
optional
types
;
associationOptions = with types; associationOptions =
attrsOf (coercedTo (either (listOf str) str) with types;
(x: lib.concatStringsSep ";" (lib.toList x)) str); attrsOf (coercedTo (either (listOf str) str) (x: lib.concatStringsSep ";" (lib.toList x)) str);
in { in
{
meta.maintainers = [ lib.maintainers.misterio77 ]; meta.maintainers = [ lib.maintainers.misterio77 ];
options.xdg.portal = { options.xdg.portal = {
@ -63,12 +75,22 @@ in {
type = types.attrsOf associationOptions; type = types.attrsOf associationOptions;
default = { }; default = { };
example = { example = {
x-cinnamon = { default = [ "xapp" "gtk" ]; }; x-cinnamon = {
default = [
"xapp"
"gtk"
];
};
pantheon = { pantheon = {
default = [ "pantheon" "gtk" ]; default = [
"pantheon"
"gtk"
];
"org.freedesktop.impl.portal.Secret" = [ "gnome-keyring" ]; "org.freedesktop.impl.portal.Secret" = [ "gnome-keyring" ];
}; };
common = { default = [ "gtk" ]; }; common = {
default = [ "gtk" ];
};
}; };
description = '' description = ''
Sets which portal backend should be used to provide the implementation Sets which portal backend should be used to provide the implementation
@ -97,12 +119,13 @@ in {
}; };
}; };
config = let config =
let
cfg = config.xdg.portal; cfg = config.xdg.portal;
packages = [ pkgs.xdg-desktop-portal ] ++ cfg.extraPortals; packages = [ pkgs.xdg-desktop-portal ] ++ cfg.extraPortals;
portalsDir = portalsDir = "${config.home.profileDirectory}/share/xdg-desktop-portal/portals";
"${config.home.profileDirectory}/share/xdg-desktop-portal/portals"; in
in mkIf cfg.enable { mkIf cfg.enable {
warnings = optional (cfg.configPackages == [ ] && cfg.config == { }) '' warnings = optional (cfg.configPackages == [ ] && cfg.config == { }) ''
xdg-desktop-portal 1.17 reworked how portal implementations are loaded, you xdg-desktop-portal 1.17 reworked how portal implementations are loaded, you
should either set `xdg.portal.config` or `xdg.portal.configPackages` should either set `xdg.portal.config` or `xdg.portal.configPackages`
@ -121,8 +144,7 @@ in {
{ {
assertion = cfg.extraPortals != [ ]; assertion = cfg.extraPortals != [ ];
message = message = "Setting xdg.portal.enable to true requires a portal implementation in xdg.portal.extraPortals such as xdg-desktop-portal-gtk or xdg-desktop-portal-kde.";
"Setting xdg.portal.enable to true requires a portal implementation in xdg.portal.extraPortals such as xdg-desktop-portal-gtk or xdg-desktop-portal-kde.";
} }
]; ];
@ -137,11 +159,13 @@ in {
NIX_XDG_DESKTOP_PORTAL_DIR = portalsDir; NIX_XDG_DESKTOP_PORTAL_DIR = portalsDir;
}; };
xdg.configFile = lib.concatMapAttrs (desktop: conf: xdg.configFile = lib.concatMapAttrs (
desktop: conf:
lib.optionalAttrs (conf != { }) { lib.optionalAttrs (conf != { }) {
"xdg-desktop-portal/${ "xdg-desktop-portal/${lib.optionalString (desktop != "common") "${desktop}-"}portals.conf".text =
lib.optionalString (desktop != "common") "${desktop}-" lib.generators.toINI { }
}portals.conf".text = lib.generators.toINI { } { preferred = conf; }; { preferred = conf; };
}) cfg.config; }
) cfg.config;
}; };
} }

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) types; inherit (lib) types;
@ -9,7 +14,8 @@ let
dataDirs = lib.concatStringsSep ":" cfg.data; dataDirs = lib.concatStringsSep ":" cfg.data;
in { in
{
meta.maintainers = with lib.maintainers; [ tadfisher ]; meta.maintainers = with lib.maintainers; [ tadfisher ];
options.xdg.systemDirs = { options.xdg.systemDirs = {
@ -37,25 +43,20 @@ in {
config = lib.mkMerge [ config = lib.mkMerge [
(lib.mkIf (cfg.config != [ ] || cfg.data != [ ]) { (lib.mkIf (cfg.config != [ ] || cfg.data != [ ]) {
assertions = [ assertions = [
(lib.hm.assertions.assertPlatform "xdg.systemDirs" pkgs (lib.hm.assertions.assertPlatform "xdg.systemDirs" pkgs lib.platforms.linux)
lib.platforms.linux)
]; ];
}) })
(lib.mkIf (cfg.config != [ ]) { (lib.mkIf (cfg.config != [ ]) {
home.sessionVariables.XDG_CONFIG_DIRS = home.sessionVariables.XDG_CONFIG_DIRS = "${configDirs}\${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}";
"${configDirs}\${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}";
systemd.user.sessionVariables.XDG_CONFIG_DIRS = systemd.user.sessionVariables.XDG_CONFIG_DIRS = "${configDirs}\${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}";
"${configDirs}\${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}";
}) })
(lib.mkIf (cfg.data != [ ]) { (lib.mkIf (cfg.data != [ ]) {
home.sessionVariables.XDG_DATA_DIRS = home.sessionVariables.XDG_DATA_DIRS = "${dataDirs}\${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}";
"${dataDirs}\${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}";
systemd.user.sessionVariables.XDG_DATA_DIRS = systemd.user.sessionVariables.XDG_DATA_DIRS = "${dataDirs}\${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}";
"${dataDirs}\${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}";
}) })
]; ];
} }

View file

@ -1,19 +1,28 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) literalExpression mkOption types; inherit (lib) literalExpression mkOption types;
cfg = config.xdg.userDirs; cfg = config.xdg.userDirs;
in { in
{
meta.maintainers = with lib.maintainers; [ euxane ]; meta.maintainers = with lib.maintainers; [ euxane ];
imports = [ imports = [
(lib.mkRenamedOptionModule [ "xdg" "userDirs" "publishShare" ] [ (lib.mkRenamedOptionModule
[ "xdg" "userDirs" "publishShare" ]
[
"xdg" "xdg"
"userDirs" "userDirs"
"publicShare" "publicShare"
]) ]
)
]; ];
options.xdg.userDirs = { options.xdg.userDirs = {
@ -33,64 +42,56 @@ in {
desktop = mkOption { desktop = mkOption {
type = with types; nullOr (coercedTo path toString str); type = with types; nullOr (coercedTo path toString str);
default = "${config.home.homeDirectory}/Desktop"; default = "${config.home.homeDirectory}/Desktop";
defaultText = defaultText = literalExpression ''"''${config.home.homeDirectory}/Desktop"'';
literalExpression ''"''${config.home.homeDirectory}/Desktop"'';
description = "The Desktop directory."; description = "The Desktop directory.";
}; };
documents = mkOption { documents = mkOption {
type = with types; nullOr (coercedTo path toString str); type = with types; nullOr (coercedTo path toString str);
default = "${config.home.homeDirectory}/Documents"; default = "${config.home.homeDirectory}/Documents";
defaultText = defaultText = literalExpression ''"''${config.home.homeDirectory}/Documents"'';
literalExpression ''"''${config.home.homeDirectory}/Documents"'';
description = "The Documents directory."; description = "The Documents directory.";
}; };
download = mkOption { download = mkOption {
type = with types; nullOr (coercedTo path toString str); type = with types; nullOr (coercedTo path toString str);
default = "${config.home.homeDirectory}/Downloads"; default = "${config.home.homeDirectory}/Downloads";
defaultText = defaultText = literalExpression ''"''${config.home.homeDirectory}/Downloads"'';
literalExpression ''"''${config.home.homeDirectory}/Downloads"'';
description = "The Downloads directory."; description = "The Downloads directory.";
}; };
music = mkOption { music = mkOption {
type = with types; nullOr (coercedTo path toString str); type = with types; nullOr (coercedTo path toString str);
default = "${config.home.homeDirectory}/Music"; default = "${config.home.homeDirectory}/Music";
defaultText = defaultText = literalExpression ''"''${config.home.homeDirectory}/Music"'';
literalExpression ''"''${config.home.homeDirectory}/Music"'';
description = "The Music directory."; description = "The Music directory.";
}; };
pictures = mkOption { pictures = mkOption {
type = with types; nullOr (coercedTo path toString str); type = with types; nullOr (coercedTo path toString str);
default = "${config.home.homeDirectory}/Pictures"; default = "${config.home.homeDirectory}/Pictures";
defaultText = defaultText = literalExpression ''"''${config.home.homeDirectory}/Pictures"'';
literalExpression ''"''${config.home.homeDirectory}/Pictures"'';
description = "The Pictures directory."; description = "The Pictures directory.";
}; };
publicShare = mkOption { publicShare = mkOption {
type = with types; nullOr (coercedTo path toString str); type = with types; nullOr (coercedTo path toString str);
default = "${config.home.homeDirectory}/Public"; default = "${config.home.homeDirectory}/Public";
defaultText = defaultText = literalExpression ''"''${config.home.homeDirectory}/Public"'';
literalExpression ''"''${config.home.homeDirectory}/Public"'';
description = "The Public share directory."; description = "The Public share directory.";
}; };
templates = mkOption { templates = mkOption {
type = with types; nullOr (coercedTo path toString str); type = with types; nullOr (coercedTo path toString str);
default = "${config.home.homeDirectory}/Templates"; default = "${config.home.homeDirectory}/Templates";
defaultText = defaultText = literalExpression ''"''${config.home.homeDirectory}/Templates"'';
literalExpression ''"''${config.home.homeDirectory}/Templates"'';
description = "The Templates directory."; description = "The Templates directory.";
}; };
videos = mkOption { videos = mkOption {
type = with types; nullOr (coercedTo path toString str); type = with types; nullOr (coercedTo path toString str);
default = "${config.home.homeDirectory}/Videos"; default = "${config.home.homeDirectory}/Videos";
defaultText = defaultText = literalExpression ''"''${config.home.homeDirectory}/Videos"'';
literalExpression ''"''${config.home.homeDirectory}/Videos"'';
description = "The Videos directory."; description = "The Videos directory.";
}; };
@ -106,12 +107,13 @@ in {
description = "Other user directories."; description = "Other user directories.";
}; };
createDirectories = createDirectories = lib.mkEnableOption "automatic creation of the XDG user directories";
lib.mkEnableOption "automatic creation of the XDG user directories";
}; };
config = let config =
directories = (lib.filterAttrs (n: v: !isNull v) { let
directories =
(lib.filterAttrs (n: v: !isNull v) {
XDG_DESKTOP_DIR = cfg.desktop; XDG_DESKTOP_DIR = cfg.desktop;
XDG_DOCUMENTS_DIR = cfg.documents; XDG_DOCUMENTS_DIR = cfg.documents;
XDG_DOWNLOAD_DIR = cfg.download; XDG_DOWNLOAD_DIR = cfg.download;
@ -120,27 +122,33 @@ in {
XDG_PUBLICSHARE_DIR = cfg.publicShare; XDG_PUBLICSHARE_DIR = cfg.publicShare;
XDG_TEMPLATES_DIR = cfg.templates; XDG_TEMPLATES_DIR = cfg.templates;
XDG_VIDEOS_DIR = cfg.videos; XDG_VIDEOS_DIR = cfg.videos;
}) // cfg.extraConfig; })
in lib.mkIf cfg.enable { // cfg.extraConfig;
in
lib.mkIf cfg.enable {
assertions = [ assertions = [
(lib.hm.assertions.assertPlatform "xdg.userDirs" pkgs lib.platforms.linux) (lib.hm.assertions.assertPlatform "xdg.userDirs" pkgs lib.platforms.linux)
]; ];
xdg.configFile."user-dirs.dirs".text = let xdg.configFile."user-dirs.dirs".text =
let
# For some reason, these need to be wrapped with quotes to be valid. # For some reason, these need to be wrapped with quotes to be valid.
wrapped = lib.mapAttrs (_: value: ''"${value}"'') directories; wrapped = lib.mapAttrs (_: value: ''"${value}"'') directories;
in lib.generators.toKeyValue { } wrapped; in
lib.generators.toKeyValue { } wrapped;
xdg.configFile."user-dirs.conf".text = "enabled=False"; xdg.configFile."user-dirs.conf".text = "enabled=False";
home.sessionVariables = directories; home.sessionVariables = directories;
home.activation.createXdgUserDirectories = lib.mkIf cfg.createDirectories home.activation.createXdgUserDirectories = lib.mkIf cfg.createDirectories (
(let let
directoriesList = lib.attrValues directories; directoriesList = lib.attrValues directories;
mkdir = mkdir = (dir: ''[[ -L "${dir}" ]] || run mkdir -p $VERBOSE_ARG "${dir}"'');
(dir: ''[[ -L "${dir}" ]] || run mkdir -p $VERBOSE_ARG "${dir}"''); in
in lib.hm.dag.entryAfter [ "linkGeneration" ] lib.hm.dag.entryAfter [ "linkGeneration" ] (
(lib.strings.concatMapStringsSep "\n" mkdir directoriesList)); lib.strings.concatMapStringsSep "\n" mkdir directoriesList
)
);
}; };
} }

View file

@ -1,11 +1,22 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkOptionDefault mkIf mkOption types; inherit (lib)
mkOptionDefault
mkIf
mkOption
types
;
cfg = config.xdg; cfg = config.xdg;
fileType = (import ../lib/file-type.nix { fileType =
(import ../lib/file-type.nix {
inherit (config.home) homeDirectory; inherit (config.home) homeDirectory;
inherit lib pkgs; inherit lib pkgs;
}).fileType; }).fileType;
@ -15,11 +26,15 @@ let
defaultDataHome = "${config.home.homeDirectory}/.local/share"; defaultDataHome = "${config.home.homeDirectory}/.local/share";
defaultStateHome = "${config.home.homeDirectory}/.local/state"; defaultStateHome = "${config.home.homeDirectory}/.local/state";
getEnvFallback = name: fallback: getEnvFallback =
let value = builtins.getEnv name; name: fallback:
in if value != "" then value else fallback; let
value = builtins.getEnv name;
in
if value != "" then value else fallback;
in { in
{
options.xdg = { options.xdg = {
enable = lib.mkEnableOption "management of XDG base directories"; enable = lib.mkEnableOption "management of XDG base directories";
@ -64,8 +79,7 @@ in {
}; };
dataFile = mkOption { dataFile = mkOption {
type = type = fileType "xdg.dataFile" "<varname>xdg.dataHome</varname>" cfg.dataHome;
fileType "xdg.dataFile" "<varname>xdg.dataHome</varname>" cfg.dataHome;
default = { }; default = { };
description = '' description = ''
Attribute set of files to link into the user's XDG Attribute set of files to link into the user's XDG
@ -85,8 +99,7 @@ in {
}; };
stateFile = mkOption { stateFile = mkOption {
type = fileType "xdg.stateFile" "<varname>xdg.stateHome</varname>" type = fileType "xdg.stateFile" "<varname>xdg.stateHome</varname>" cfg.stateHome;
cfg.stateHome;
default = { }; default = { };
description = '' description = ''
Attribute set of files to link into the user's XDG Attribute set of files to link into the user's XDG
@ -107,34 +120,32 @@ in {
}; };
config = lib.mkMerge [ config = lib.mkMerge [
(let (
let
variables = { variables = {
XDG_CACHE_HOME = cfg.cacheHome; XDG_CACHE_HOME = cfg.cacheHome;
XDG_CONFIG_HOME = cfg.configHome; XDG_CONFIG_HOME = cfg.configHome;
XDG_DATA_HOME = cfg.dataHome; XDG_DATA_HOME = cfg.dataHome;
XDG_STATE_HOME = cfg.stateHome; XDG_STATE_HOME = cfg.stateHome;
}; };
in mkIf cfg.enable { in
mkIf cfg.enable {
xdg.cacheHome = mkOptionDefault defaultCacheHome; xdg.cacheHome = mkOptionDefault defaultCacheHome;
xdg.configHome = mkOptionDefault defaultConfigHome; xdg.configHome = mkOptionDefault defaultConfigHome;
xdg.dataHome = mkOptionDefault defaultDataHome; xdg.dataHome = mkOptionDefault defaultDataHome;
xdg.stateHome = mkOptionDefault defaultStateHome; xdg.stateHome = mkOptionDefault defaultStateHome;
home.sessionVariables = variables; home.sessionVariables = variables;
systemd.user.sessionVariables = systemd.user.sessionVariables = mkIf pkgs.stdenv.hostPlatform.isLinux variables;
mkIf pkgs.stdenv.hostPlatform.isLinux variables; }
}) )
# Legacy non-deterministic setup. # Legacy non-deterministic setup.
(mkIf (!cfg.enable && lib.versionOlder config.home.stateVersion "20.09") { (mkIf (!cfg.enable && lib.versionOlder config.home.stateVersion "20.09") {
xdg.cacheHome = xdg.cacheHome = mkOptionDefault (getEnvFallback "XDG_CACHE_HOME" defaultCacheHome);
mkOptionDefault (getEnvFallback "XDG_CACHE_HOME" defaultCacheHome); xdg.configHome = mkOptionDefault (getEnvFallback "XDG_CONFIG_HOME" defaultConfigHome);
xdg.configHome = xdg.dataHome = mkOptionDefault (getEnvFallback "XDG_DATA_HOME" defaultDataHome);
mkOptionDefault (getEnvFallback "XDG_CONFIG_HOME" defaultConfigHome); xdg.stateHome = mkOptionDefault (getEnvFallback "XDG_STATE_HOME" defaultStateHome);
xdg.dataHome =
mkOptionDefault (getEnvFallback "XDG_DATA_HOME" defaultDataHome);
xdg.stateHome =
mkOptionDefault (getEnvFallback "XDG_STATE_HOME" defaultStateHome);
}) })
# "Modern" deterministic setup. # "Modern" deterministic setup.
@ -147,18 +158,10 @@ in {
{ {
home.file = lib.mkMerge [ home.file = lib.mkMerge [
(lib.mapAttrs' (lib.mapAttrs' (name: file: lib.nameValuePair "${cfg.cacheHome}/${name}" file) cfg.cacheFile)
(name: file: lib.nameValuePair "${cfg.cacheHome}/${name}" file) (lib.mapAttrs' (name: file: lib.nameValuePair "${cfg.configHome}/${name}" file) cfg.configFile)
cfg.cacheFile) (lib.mapAttrs' (name: file: lib.nameValuePair "${cfg.dataHome}/${name}" file) cfg.dataFile)
(lib.mapAttrs' (lib.mapAttrs' (name: file: lib.nameValuePair "${cfg.stateHome}/${name}" file) cfg.stateFile)
(name: file: lib.nameValuePair "${cfg.configHome}/${name}" file)
cfg.configFile)
(lib.mapAttrs'
(name: file: lib.nameValuePair "${cfg.dataHome}/${name}" file)
cfg.dataFile)
(lib.mapAttrs'
(name: file: lib.nameValuePair "${cfg.stateHome}/${name}" file)
cfg.stateFile)
{ "${cfg.cacheHome}/.keep".text = ""; } { "${cfg.cacheHome}/.keep".text = ""; }
{ "${cfg.stateHome}/.keep".text = ""; } { "${cfg.stateHome}/.keep".text = ""; }
]; ];

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkOption types; inherit (lib) mkOption types;
@ -8,7 +13,11 @@ let
xfIntVariant = types.submodule { xfIntVariant = types.submodule {
options = { options = {
type = mkOption { type = mkOption {
type = types.enum [ "int" "uint" "uint64" ]; type = types.enum [
"int"
"uint"
"uint64"
];
description = '' description = ''
To distinguish between int, uint and uint64 in xfconf, To distinguish between int, uint and uint64 in xfconf,
you can specify the type in xfconf with this submodule. you can specify the type in xfconf with this submodule.
@ -23,38 +32,50 @@ let
}; };
}; };
withType = v: withType =
if builtins.isAttrs v then [ v:
if builtins.isAttrs v then
[
"-t" "-t"
v.type v.type
"-s" "-s"
(toString v.value) (toString v.value)
] else if builtins.isBool v then [ ]
else if builtins.isBool v then
[
"-t" "-t"
"bool" "bool"
"-s" "-s"
(if v then "true" else "false") (if v then "true" else "false")
] else if builtins.isInt v then [ ]
else if builtins.isInt v then
[
"-t" "-t"
"int" "int"
"-s" "-s"
(toString v) (toString v)
] else if builtins.isFloat v then [ ]
else if builtins.isFloat v then
[
"-t" "-t"
"double" "double"
"-s" "-s"
(toString v) (toString v)
] else if builtins.isString v then [ ]
else if builtins.isString v then
[
"-t" "-t"
"string" "string"
"-s" "-s"
v v
] else if builtins.isList v then ]
else if builtins.isList v then
[ "-a" ] ++ lib.concatMap withType v [ "-a" ] ++ lib.concatMap withType v
else else
throw "unexpected xfconf type: ${builtins.typeOf v}"; throw "unexpected xfconf type: ${builtins.typeOf v}";
in { in
{
meta.maintainers = [ lib.maintainers.chuangzhu ]; meta.maintainers = [ lib.maintainers.chuangzhu ];
options.xfconf = { options.xfconf = {
@ -73,10 +94,20 @@ in {
}; };
settings = mkOption { settings = mkOption {
type = with types; type =
with types;
# xfIntVariant must come AFTER str; otherwise strings are treated as submodule imports... # xfIntVariant must come AFTER str; otherwise strings are treated as submodule imports...
let value = nullOr (oneOf [ bool int float str xfIntVariant ]); let
in attrsOf (attrsOf (either value (listOf value))) // { value = nullOr (oneOf [
bool
int
float
str
xfIntVariant
]);
in
attrsOf (attrsOf (either value (listOf value)))
// {
description = "xfconf settings"; description = "xfconf settings";
}; };
default = { }; default = { };
@ -99,30 +130,33 @@ in {
}; };
config = lib.mkIf (cfg.enable && cfg.settings != { }) { config = lib.mkIf (cfg.enable && cfg.settings != { }) {
assertions = assertions = [ (lib.hm.assertions.assertPlatform "xfconf" pkgs lib.platforms.linux) ];
[ (lib.hm.assertions.assertPlatform "xfconf" pkgs lib.platforms.linux) ];
home.activation.xfconfSettings = lib.hm.dag.entryAfter [ "installPackages" ] home.activation.xfconfSettings = lib.hm.dag.entryAfter [ "installPackages" ] (
(let let
mkCommand = channel: property: value: '' mkCommand = channel: property: value: ''
run ${pkgs.xfce.xfconf}/bin/xfconf-query \ run ${pkgs.xfce.xfconf}/bin/xfconf-query \
${ ${lib.escapeShellArgs (
lib.escapeShellArgs ([ "-c" channel "-p" "/${property}" ] [
++ (if value == null then "-c"
[ "-r" ] channel
else "-p"
[ "-n" ] ++ withType value)) "/${property}"
} ]
++ (if value == null then [ "-r" ] else [ "-n" ] ++ withType value)
)}
''; '';
commands = lib.mapAttrsToList (channel: properties: commands = lib.mapAttrsToList (
lib.mapAttrsToList (mkCommand channel) properties) cfg.settings; channel: properties: lib.mapAttrsToList (mkCommand channel) properties
) cfg.settings;
load = pkgs.writeShellScript "load-xfconf" '' load = pkgs.writeShellScript "load-xfconf" ''
${config.lib.bash.initHomeManagerLib} ${config.lib.bash.initHomeManagerLib}
${lib.concatMapStrings lib.concatStrings commands} ${lib.concatMapStrings lib.concatStrings commands}
''; '';
in '' in
''
if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then
export DBUS_RUN_SESSION_CMD="" export DBUS_RUN_SESSION_CMD=""
else else
@ -132,6 +166,7 @@ in {
run $DBUS_RUN_SESSION_CMD ${load} run $DBUS_RUN_SESSION_CMD ${load}
unset DBUS_RUN_SESSION_CMD unset DBUS_RUN_SESSION_CMD
''); ''
);
}; };
} }

View file

@ -1,17 +1,20 @@
{ pkgs {
pkgs,
# Note, this should be "the standard library" + HM extensions. # Note, this should be "the standard library" + HM extensions.
, lib lib,
# Whether to enable module type checking. # Whether to enable module type checking.
, check ? true check ? true,
# If disabled, the pkgs attribute passed to this function is used instead. # If disabled, the pkgs attribute passed to this function is used instead.
, useNixpkgsModule ? true }: useNixpkgsModule ? true,
}:
let let
modules = [ modules =
[
./accounts/email.nix ./accounts/email.nix
./accounts/calendar.nix ./accounts/calendar.nix
./accounts/contacts.nix ./accounts/contacts.nix
@ -470,23 +473,27 @@ let
(lib.mkRemovedOptionModule [ "services" "keepassx" ] '' (lib.mkRemovedOptionModule [ "services" "keepassx" ] ''
KeePassX is no longer maintained. KeePassX is no longer maintained.
'') '')
] ++ lib.optional useNixpkgsModule ./misc/nixpkgs.nix ]
++ lib.optional useNixpkgsModule ./misc/nixpkgs.nix
++ lib.optional (!useNixpkgsModule) ./misc/nixpkgs-disabled.nix; ++ lib.optional (!useNixpkgsModule) ./misc/nixpkgs-disabled.nix;
pkgsModule = { config, ... }: { pkgsModule =
config = { { config, ... }:
{
config =
{
_module.args.baseModules = modules; _module.args.baseModules = modules;
_module.args.pkgsPath = lib.mkDefault _module.args.pkgsPath = lib.mkDefault (
(if lib.versionAtLeast config.home.stateVersion "20.09" then if lib.versionAtLeast config.home.stateVersion "20.09" then pkgs.path else <nixpkgs>
pkgs.path );
else
<nixpkgs>);
_module.args.pkgs = lib.mkDefault pkgs; _module.args.pkgs = lib.mkDefault pkgs;
_module.check = check; _module.check = check;
lib = lib.hm; lib = lib.hm;
} // lib.optionalAttrs useNixpkgsModule { }
// lib.optionalAttrs useNixpkgsModule {
nixpkgs.system = lib.mkDefault pkgs.stdenv.hostPlatform.system; nixpkgs.system = lib.mkDefault pkgs.stdenv.hostPlatform.system;
}; };
}; };
in modules ++ [ pkgsModule ] in
modules ++ [ pkgsModule ]

View file

@ -1,6 +1,13 @@
{ config, lib, pkgs, ... }: {
let cfg = config.programs.abook; config,
in { lib,
pkgs,
...
}:
let
cfg = config.programs.abook;
in
{
options.programs.abook = { options.programs.abook = {
enable = lib.mkEnableOption "Abook"; enable = lib.mkEnableOption "Abook";

View file

@ -1,17 +1,29 @@
{ config, lib, confSections, confSection, ... }: {
config,
lib,
confSections,
confSection,
...
}:
let let
inherit (lib) literalExpression mkOption types; inherit (lib) literalExpression mkOption types;
mapAttrNames = f: attr: mapAttrNames =
lib.listToAttrs (lib.attrValues (lib.mapAttrs (k: v: { f: attr:
lib.listToAttrs (
lib.attrValues (
lib.mapAttrs (k: v: {
name = f k; name = f k;
value = v; value = v;
}) attr)); }) attr
)
);
addAccountName = name: k: "${k}:account=${name}"; addAccountName = name: k: "${k}:account=${name}";
oauth2Params = mkOption { oauth2Params = mkOption {
type = with types; type =
with types;
nullOr (submodule { nullOr (submodule {
options = { options = {
token_endpoint = mkOption { token_endpoint = mkOption {
@ -37,7 +49,9 @@ let
}; };
}); });
default = null; default = null;
example = { token_endpoint = "<token_endpoint>"; }; example = {
token_endpoint = "<token_endpoint>";
};
description = '' description = ''
Sets the oauth2 params if authentication mechanism oauthbearer or Sets the oauth2 params if authentication mechanism oauthbearer or
xoauth2 is used. xoauth2 is used.
@ -45,16 +59,17 @@ let
''; '';
}; };
in { in
{
type = mkOption { type = mkOption {
type = types.attrsOf (types.submodule { type = types.attrsOf (
types.submodule {
options.aerc = { options.aerc = {
enable = lib.mkEnableOption "aerc"; enable = lib.mkEnableOption "aerc";
extraAccounts = mkOption { extraAccounts = mkOption {
type = confSection; type = confSection;
default = { }; default = { };
example = example = literalExpression ''{ source = "maildir://~/Maildir/example"; }'';
literalExpression ''{ source = "maildir://~/Maildir/example"; }'';
description = '' description = ''
Extra config added to the configuration section for this account in Extra config added to the configuration section for this account in
{file}`$HOME/.config/aerc/accounts.conf`. {file}`$HOME/.config/aerc/accounts.conf`.
@ -65,8 +80,7 @@ in {
extraBinds = mkOption { extraBinds = mkOption {
type = confSections; type = confSections;
default = { }; default = { };
example = literalExpression example = literalExpression ''{ messages = { d = ":move ''${folder.trash}<Enter>"; }; }'';
''{ messages = { d = ":move ''${folder.trash}<Enter>"; }; }'';
description = '' description = ''
Extra bindings specific to this account, added to Extra bindings specific to this account, added to
{file}`$HOME/.config/aerc/binds.conf`. {file}`$HOME/.config/aerc/binds.conf`.
@ -88,7 +102,12 @@ in {
}; };
imapAuth = mkOption { imapAuth = mkOption {
type = with types; nullOr (enum [ "oauthbearer" "xoauth2" ]); type =
with types;
nullOr (enum [
"oauthbearer"
"xoauth2"
]);
default = null; default = null;
example = "auth"; example = "auth";
description = '' description = ''
@ -101,8 +120,15 @@ in {
imapOauth2Params = oauth2Params; imapOauth2Params = oauth2Params;
smtpAuth = mkOption { smtpAuth = mkOption {
type = with types; type =
nullOr (enum [ "none" "plain" "login" "oauthbearer" "xoauth2" ]); with types;
nullOr (enum [
"none"
"plain"
"login"
"oauthbearer"
"xoauth2"
]);
default = "plain"; default = "plain";
example = "auth"; example = "auth";
description = '' description = ''
@ -114,88 +140,107 @@ in {
smtpOauth2Params = oauth2Params; smtpOauth2Params = oauth2Params;
}; };
}); }
);
}; };
mkAccount = name: account: mkAccount =
name: account:
let let
nullOrMap = f: v: if v == null then v else f v; nullOrMap = f: v: if v == null then v else f v;
optPort = port: if port != null then ":${toString port}" else ""; optPort = port: if port != null then ":${toString port}" else "";
optAttr = k: v: optAttr = k: v: if v != null && v != [ ] && v != "" then { ${k} = v; } else { };
if v != null && v != [ ] && v != "" then { ${k} = v; } else { };
optPwCmd = k: p: optPwCmd = k: p: optAttr "${k}-cred-cmd" (nullOrMap (lib.concatStringsSep " ") p);
optAttr "${k}-cred-cmd" (nullOrMap (lib.concatStringsSep " ") p);
useOauth = auth: builtins.elem auth [ "oauthbearer" "xoauth2" ]; useOauth =
auth:
builtins.elem auth [
"oauthbearer"
"xoauth2"
];
oauthParams = { auth, params }: oauthParams =
{ auth, params }:
if useOauth auth && params != null && params != { } then if useOauth auth && params != null && params != { } then
"?" + builtins.concatStringsSep "&" "?"
(lib.attrsets.mapAttrsToList (k: v: k + "=" + lib.strings.escapeURL v) + builtins.concatStringsSep "&" (
(lib.attrsets.filterAttrs (k: v: v != null) params)) lib.attrsets.mapAttrsToList (k: v: k + "=" + lib.strings.escapeURL v) (
lib.attrsets.filterAttrs (k: v: v != null) params
)
)
else else
""; "";
mkConfig = { mkConfig = {
maildir = cfg: { maildir = cfg: {
source = source = "maildir://${config.accounts.email.maildirBasePath}/${cfg.maildir.path}";
"maildir://${config.accounts.email.maildirBasePath}/${cfg.maildir.path}";
}; };
maildirpp = cfg: { maildirpp = cfg: {
source = source = "maildirpp://${config.accounts.email.maildirBasePath}/${cfg.maildir.path}/Inbox";
"maildirpp://${config.accounts.email.maildirBasePath}/${cfg.maildir.path}/Inbox";
}; };
imap = { userName, imap, passwordCommand, aerc, ... }@cfg: imap =
{
userName,
imap,
passwordCommand,
aerc,
...
}@cfg:
let let
loginMethod' = loginMethod' = if cfg.aerc.imapAuth != null then "+${cfg.aerc.imapAuth}" else "";
if cfg.aerc.imapAuth != null then "+${cfg.aerc.imapAuth}" else "";
oauthParams' = oauthParams { oauthParams' = oauthParams {
auth = cfg.aerc.imapAuth; auth = cfg.aerc.imapAuth;
params = cfg.aerc.imapOauth2Params; params = cfg.aerc.imapOauth2Params;
}; };
protocol = if imap.tls.enable then protocol =
if imap.tls.enable then
if imap.tls.useStartTls then "imap" else "imaps${loginMethod'}" if imap.tls.useStartTls then "imap" else "imaps${loginMethod'}"
else else
"imap+insecure"; "imap+insecure";
port' = optPort imap.port; port' = optPort imap.port;
in { in
source = {
"${protocol}://${userName}@${imap.host}${port'}${oauthParams'}"; source = "${protocol}://${userName}@${imap.host}${port'}${oauthParams'}";
} // optPwCmd "source" passwordCommand; }
// optPwCmd "source" passwordCommand;
smtp = { userName, smtp, passwordCommand, ... }@cfg: smtp =
{
userName,
smtp,
passwordCommand,
...
}@cfg:
let let
loginMethod' = loginMethod' = if cfg.aerc.smtpAuth != null then "+${cfg.aerc.smtpAuth}" else "";
if cfg.aerc.smtpAuth != null then "+${cfg.aerc.smtpAuth}" else "";
oauthParams' = oauthParams { oauthParams' = oauthParams {
auth = cfg.aerc.smtpAuth; auth = cfg.aerc.smtpAuth;
params = cfg.aerc.smtpOauth2Params; params = cfg.aerc.smtpOauth2Params;
}; };
protocol = if smtp.tls.enable then protocol =
if smtp.tls.useStartTls then if smtp.tls.enable then
"smtp${loginMethod'}" if smtp.tls.useStartTls then "smtp${loginMethod'}" else "smtps${loginMethod'}"
else
"smtps${loginMethod'}"
else else
"smtp+insecure${loginMethod'}"; "smtp+insecure${loginMethod'}";
port' = optPort smtp.port; port' = optPort smtp.port;
in { in
outgoing = {
"${protocol}://${userName}@${smtp.host}${port'}${oauthParams'}"; outgoing = "${protocol}://${userName}@${smtp.host}${port'}${oauthParams'}";
} // optPwCmd "outgoing" passwordCommand; }
// optPwCmd "outgoing" passwordCommand;
msmtp = cfg: { msmtp = cfg: {
outgoing = "msmtpq --read-envelope-from --read-recipients"; outgoing = "msmtpq --read-envelope-from --read-recipients";
@ -203,17 +248,21 @@ in {
}; };
basicCfg = account: basicCfg =
account:
{ {
from = "${account.realName} <${account.address}>"; from = "${account.realName} <${account.address}>";
} // (optAttr "copy-to" account.folders.sent) }
// (optAttr "copy-to" account.folders.sent)
// (optAttr "default" account.folders.inbox) // (optAttr "default" account.folders.inbox)
// (optAttr "postpone" account.folders.drafts) // (optAttr "postpone" account.folders.drafts)
// (optAttr "aliases" account.aliases); // (optAttr "aliases" account.aliases);
sourceCfg = account: sourceCfg =
if account.mbsync.enable && account.mbsync.flatten == null account:
&& account.mbsync.subFolders == "Maildir++" then if
account.mbsync.enable && account.mbsync.flatten == null && account.mbsync.subFolders == "Maildir++"
then
mkConfig.maildirpp account mkConfig.maildirpp account
else if account.mbsync.enable || account.offlineimap.enable then else if account.mbsync.enable || account.offlineimap.enable then
mkConfig.maildir account mkConfig.maildir account
@ -222,7 +271,8 @@ in {
else else
{ }; { };
outgoingCfg = account: outgoingCfg =
account:
if account.msmtp.enable then if account.msmtp.enable then
mkConfig.msmtp account mkConfig.msmtp account
else if account.smtp != null then else if account.smtp != null then
@ -230,19 +280,22 @@ in {
else else
{ }; { };
gpgCfg = account: gpgCfg =
account:
lib.optionalAttrs (account.gpg != null) { lib.optionalAttrs (account.gpg != null) {
pgp-key-id = account.gpg.key; pgp-key-id = account.gpg.key;
pgp-auto-sign = account.gpg.signByDefault; pgp-auto-sign = account.gpg.signByDefault;
pgp-opportunistic-encrypt = account.gpg.encryptByDefault; pgp-opportunistic-encrypt = account.gpg.encryptByDefault;
}; };
in (basicCfg account) // (sourceCfg account) // (outgoingCfg account) in
// (gpgCfg account) // account.aerc.extraAccounts; (basicCfg account)
// (sourceCfg account)
// (outgoingCfg account)
// (gpgCfg account)
// account.aerc.extraAccounts;
mkAccountConfig = name: account: mkAccountConfig = name: account: mapAttrNames (addAccountName name) account.aerc.extraConfig;
mapAttrNames (addAccountName name) account.aerc.extraConfig;
mkAccountBinds = name: account: mkAccountBinds = name: account: mapAttrNames (addAccountName name) account.aerc.extraBinds;
mapAttrNames (addAccountName name) account.aerc.extraBinds;
} }

View file

@ -1,15 +1,34 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) inherit (lib)
attrsets generators literalExpression mapAttrs mkIf mkOption types; attrsets
generators
literalExpression
mapAttrs
mkIf
mkOption
types
;
cfg = config.programs.aerc; cfg = config.programs.aerc;
primitive = with types; primitive =
((type: either type (listOf type)) (nullOr (oneOf [ str int bool float ]))) with types;
((type: either type (listOf type)) (
nullOr (oneOf [
str
int
bool
float
])
))
// { // {
description = description = "values (null, bool, int, string, or float) or a list of values, that will be joined with a comma";
"values (null, bool, int, string, or float) or a list of values, that will be joined with a comma";
}; };
confSection = types.attrsOf primitive; confSection = types.attrsOf primitive;
@ -19,18 +38,25 @@ let
sectionsOrLines = types.either types.lines confSections; sectionsOrLines = types.either types.lines confSections;
accounts = import ./aerc-accounts.nix { accounts = import ./aerc-accounts.nix {
inherit config pkgs lib confSection confSections; inherit
config
pkgs
lib
confSection
confSections
;
}; };
aerc-accounts = aerc-accounts = attrsets.filterAttrs (_: v: v.aerc.enable) config.accounts.email.accounts;
attrsets.filterAttrs (_: v: v.aerc.enable) config.accounts.email.accounts;
configDir = if (pkgs.stdenv.isDarwin && !config.xdg.enable) then configDir =
if (pkgs.stdenv.isDarwin && !config.xdg.enable) then
"Library/Preferences/aerc" "Library/Preferences/aerc"
else else
"${config.xdg.configHome}/aerc"; "${config.xdg.configHome}/aerc";
in { in
{
meta.maintainers = with lib.hm.maintainers; [ lukasngl ]; meta.maintainers = with lib.hm.maintainers; [ lukasngl ];
options.accounts.email.accounts = accounts.type; options.accounts.email.accounts = accounts.type;
@ -44,8 +70,7 @@ in {
extraAccounts = mkOption { extraAccounts = mkOption {
type = sectionsOrLines; type = sectionsOrLines;
default = { }; default = { };
example = literalExpression example = literalExpression ''{ Work = { source = "maildir://~/Maildir/work"; }; }'';
''{ Work = { source = "maildir://~/Maildir/work"; }; }'';
description = '' description = ''
Extra lines added to {file}`$HOME/.config/aerc/accounts.conf`. Extra lines added to {file}`$HOME/.config/aerc/accounts.conf`.
@ -103,39 +128,50 @@ in {
}; };
}; };
config = let config =
let
joinCfg = cfgs: lib.concatStringsSep "\n" (lib.filter (v: v != "") cfgs); joinCfg = cfgs: lib.concatStringsSep "\n" (lib.filter (v: v != "") cfgs);
toINI = conf: # quirk: global section is prepended w/o section heading toINI =
conf: # quirk: global section is prepended w/o section heading
let let
global = conf.global or { }; global = conf.global or { };
local = removeAttrs conf [ "global" ]; local = removeAttrs conf [ "global" ];
mkValueString = v: mkValueString =
v:
if lib.isList v then # join with comma if lib.isList v then # join with comma
lib.concatStringsSep "," lib.concatStringsSep "," (map (generators.mkValueStringDefault { }) v)
(map (generators.mkValueStringDefault { }) v)
else else
generators.mkValueStringDefault { } v; generators.mkValueStringDefault { } v;
mkKeyValue = mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } " = ";
generators.mkKeyValueDefault { inherit mkValueString; } " = "; in
in joinCfg [ joinCfg [
(generators.toKeyValue { inherit mkKeyValue; } global) (generators.toKeyValue { inherit mkKeyValue; } global)
(generators.toINI { inherit mkKeyValue; } local) (generators.toINI { inherit mkKeyValue; } local)
]; ];
mkINI = conf: if lib.isString conf then conf else toINI conf; mkINI = conf: if lib.isString conf then conf else toINI conf;
mkStyleset = attrsets.mapAttrs' (k: v: mkStyleset = attrsets.mapAttrs' (
let value = if lib.isString v then v else toINI { global = v; }; k: v:
in { let
value = if lib.isString v then v else toINI { global = v; };
in
{
name = "${configDir}/stylesets/${k}"; name = "${configDir}/stylesets/${k}";
value.text = joinCfg [ header value ]; value.text = joinCfg [
}); header
value
];
}
);
mkTemplates = attrsets.mapAttrs' (k: v: { mkTemplates = attrsets.mapAttrs' (
k: v: {
name = "${configDir}/templates/${k}"; name = "${configDir}/templates/${k}";
value.text = v; value.text = v;
}); }
);
primaryAccount = attrsets.filterAttrs (_: v: v.primary) aerc-accounts; primaryAccount = attrsets.filterAttrs (_: v: v.primary) aerc-accounts;
otherAccounts = attrsets.filterAttrs (_: v: !v.primary) aerc-accounts; otherAccounts = attrsets.filterAttrs (_: v: !v.primary) aerc-accounts;
@ -148,32 +184,36 @@ in {
accountsExtraBinds = mapAttrs accounts.mkAccountBinds aerc-accounts; accountsExtraBinds = mapAttrs accounts.mkAccountBinds aerc-accounts;
joinContextual = contextual: joinContextual = contextual: joinCfg (map mkINI (lib.attrValues contextual));
joinCfg (map mkINI (lib.attrValues contextual));
isRecursivelyEmpty = x: isRecursivelyEmpty =
if lib.isAttrs x then x:
lib.all (x: x == { } || isRecursivelyEmpty x) (lib.attrValues x) if lib.isAttrs x then lib.all (x: x == { } || isRecursivelyEmpty x) (lib.attrValues x) else false;
else
false;
genAccountsConf = ((cfg.extraAccounts != "" && cfg.extraAccounts != { }) genAccountsConf = (
(cfg.extraAccounts != "" && cfg.extraAccounts != { })
|| !(isRecursivelyEmpty accountsExtraAccounts) || !(isRecursivelyEmpty accountsExtraAccounts)
|| !(isRecursivelyEmpty primaryAccountAccounts)); || !(isRecursivelyEmpty primaryAccountAccounts)
);
genAercConf = ((cfg.extraConfig != "" && cfg.extraConfig != { }) genAercConf = (
|| !(isRecursivelyEmpty accountsExtraConfig)); (cfg.extraConfig != "" && cfg.extraConfig != { }) || !(isRecursivelyEmpty accountsExtraConfig)
);
genBindsConf = ((cfg.extraBinds != "" && cfg.extraBinds != { }) genBindsConf = (
|| !(isRecursivelyEmpty accountsExtraBinds)); (cfg.extraBinds != "" && cfg.extraBinds != { }) || !(isRecursivelyEmpty accountsExtraBinds)
);
header = '' header = ''
# Generated by Home Manager. # Generated by Home Manager.
''; '';
in mkIf cfg.enable { in
warnings = if genAccountsConf mkIf cfg.enable {
&& (cfg.extraConfig.general.unsafe-accounts-conf or false) == false then ['' warnings =
if genAccountsConf && (cfg.extraConfig.general.unsafe-accounts-conf or false) == false then
[
''
aerc: `programs.aerc.enable` is set, but `...extraConfig.general.unsafe-accounts-conf` is set to false or unset. aerc: `programs.aerc.enable` is set, but `...extraConfig.general.unsafe-accounts-conf` is set to false or unset.
This will prevent aerc from starting; see `unsafe-accounts-conf` in the man page aerc-config(5): This will prevent aerc from starting; see `unsafe-accounts-conf` in the man page aerc-config(5):
> By default, the file permissions of accounts.conf must be restrictive and only allow reading by the file owner (0600). > By default, the file permissions of accounts.conf must be restrictive and only allow reading by the file owner (0600).
@ -181,25 +221,32 @@ in {
These permissions are not possible with home-manager, since the generated file is in the nix-store (permissions 0444). These permissions are not possible with home-manager, since the generated file is in the nix-store (permissions 0444).
Therefore, please set `programs.aerc.extraConfig.general.unsafe-accounts-conf = true`. Therefore, please set `programs.aerc.extraConfig.general.unsafe-accounts-conf = true`.
This option is safe; if `passwordCommand` is properly set, no credentials will be written to the nix store. This option is safe; if `passwordCommand` is properly set, no credentials will be written to the nix store.
''] else ''
]
else
[ ]; [ ];
assertions = [{ assertions = [
assertion = let {
extraConfigSections = (lib.unique (lib.flatten assertion =
(lib.mapAttrsToList (_: v: lib.attrNames v.aerc.extraConfig) let
aerc-accounts))); extraConfigSections = (
in extraConfigSections == [ ] || extraConfigSections == [ "ui" ]; lib.unique (lib.flatten (lib.mapAttrsToList (_: v: lib.attrNames v.aerc.extraConfig) aerc-accounts))
);
in
extraConfigSections == [ ] || extraConfigSections == [ "ui" ];
message = '' message = ''
Only the ui section of $XDG_CONFIG_HOME/aerc.conf supports contextual (per-account) configuration. Only the ui section of $XDG_CONFIG_HOME/aerc.conf supports contextual (per-account) configuration.
Please configure it with accounts.email.accounts._.aerc.extraConfig.ui and move any other Please configure it with accounts.email.accounts._.aerc.extraConfig.ui and move any other
configuration to programs.aerc.extraConfig. configuration to programs.aerc.extraConfig.
''; '';
}]; }
];
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
home.file = { home.file =
{
"${configDir}/accounts.conf" = mkIf genAccountsConf { "${configDir}/accounts.conf" = mkIf genAccountsConf {
text = joinCfg [ text = joinCfg [
header header
@ -224,6 +271,8 @@ in {
(joinContextual accountsExtraBinds) (joinContextual accountsExtraBinds)
]; ];
}; };
} // (mkStyleset cfg.stylesets) // (mkTemplates cfg.templates); }
// (mkStyleset cfg.stylesets)
// (mkTemplates cfg.templates);
}; };
} }

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkOption types; inherit (lib) mkOption types;
cfg = config.programs.aerospace; cfg = config.programs.aerospace;
@ -6,22 +11,29 @@ let
tomlFormat = pkgs.formats.toml { }; tomlFormat = pkgs.formats.toml { };
# filterAttrsRecursive supporting lists, as well. # filterAttrsRecursive supporting lists, as well.
filterListAndAttrsRecursive = pred: set: filterListAndAttrsRecursive =
lib.listToAttrs (lib.concatMap (name: pred: set:
let v = set.${name}; lib.listToAttrs (
in if pred v then lib.concatMap (
name:
let
v = set.${name};
in
if pred v then
[ [
(lib.nameValuePair name (if lib.isAttrs v then (lib.nameValuePair name (
if lib.isAttrs v then
filterListAndAttrsRecursive pred v filterListAndAttrsRecursive pred v
else if lib.isList v then else if lib.isList v then
(map (i: (map (i: if lib.isAttrs i then filterListAndAttrsRecursive pred i else i) (lib.filter pred v))
if lib.isAttrs i then filterListAndAttrsRecursive pred i else i)
(lib.filter pred v))
else else
v)) v
))
] ]
else else
[ ]) (lib.attrNames set)); [ ]
) (lib.attrNames set)
);
filterNulls = filterListAndAttrsRecursive (v: v != null); filterNulls = filterListAndAttrsRecursive (v: v != null);
# Turns # Turns
@ -30,16 +42,22 @@ let
# {"if.foo" = "xxx"; "if.bar" = "yyy"} # {"if.foo" = "xxx"; "if.bar" = "yyy"}
# so that the correct TOML is generated for the # so that the correct TOML is generated for the
# on-window-detected table. # on-window-detected table.
flattenConditions = attrs: flattenConditions =
let conditions = attrs."if" or { }; attrs:
in builtins.removeAttrs attrs [ "if" ] let
// lib.concatMapAttrs (n: v: { "if.${n}" = v; }) conditions; conditions = attrs."if" or { };
in
builtins.removeAttrs attrs [ "if" ] // lib.concatMapAttrs (n: v: { "if.${n}" = v; }) conditions;
flattenOnWindowDetected = cfg: flattenOnWindowDetected =
let owd = cfg.on-window-detected or [ ]; cfg:
in cfg // { on-window-detected = map flattenConditions owd; }; let
owd = cfg.on-window-detected or [ ];
in
cfg // { on-window-detected = map flattenConditions owd; };
in { in
{
meta.maintainers = with lib.hm.maintainers; [ damidoug ]; meta.maintainers = with lib.hm.maintainers; [ damidoug ];
options.programs.aerospace = { options.programs.aerospace = {
@ -76,15 +94,12 @@ in {
enable-normalization-flatten-containers = mkOption { enable-normalization-flatten-containers = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
description = description = ''Containers that have only one child are "flattened".'';
''Containers that have only one child are "flattened".'';
}; };
enable-normalization-opposite-orientation-for-nested-containers = enable-normalization-opposite-orientation-for-nested-containers = mkOption {
mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
description = description = "Containers that nest into each other must have opposite orientations.";
"Containers that nest into each other must have opposite orientations.";
}; };
accordion-padding = mkOption { accordion-padding = mkOption {
type = types.int; type = types.int;
@ -92,17 +107,25 @@ in {
description = "Padding between windows in an accordion container."; description = "Padding between windows in an accordion container.";
}; };
default-root-container-layout = mkOption { default-root-container-layout = mkOption {
type = types.enum [ "tiles" "accordion" ]; type = types.enum [
"tiles"
"accordion"
];
default = "tiles"; default = "tiles";
description = "Default layout for the root container."; description = "Default layout for the root container.";
}; };
default-root-container-orientation = mkOption { default-root-container-orientation = mkOption {
type = types.enum [ "horizontal" "vertical" "auto" ]; type = types.enum [
"horizontal"
"vertical"
"auto"
];
default = "auto"; default = "auto";
description = "Default orientation for the root container."; description = "Default orientation for the root container.";
}; };
on-window-detected = mkOption { on-window-detected = mkOption {
type = types.listOf (types.submodule { type = types.listOf (
types.submodule {
options = { options = {
"if" = mkOption { "if" = mkOption {
type = types.submodule { type = types.submodule {
@ -120,20 +143,17 @@ in {
window-title-regex-substring = mkOption { window-title-regex-substring = mkOption {
type = with types; nullOr str; type = with types; nullOr str;
default = null; default = null;
description = description = "Substring to match in the window title (optional).";
"Substring to match in the window title (optional).";
}; };
app-name-regex-substring = mkOption { app-name-regex-substring = mkOption {
type = with types; nullOr str; type = with types; nullOr str;
default = null; default = null;
description = description = "Regex substring to match the app name (optional).";
"Regex substring to match the app name (optional).";
}; };
during-aerospace-startup = mkOption { during-aerospace-startup = mkOption {
type = with types; nullOr bool; type = with types; nullOr bool;
default = null; default = null;
description = description = "Whether to match during aerospace startup (optional).";
"Whether to match during aerospace startup (optional).";
}; };
}; };
}; };
@ -143,19 +163,27 @@ in {
check-further-callbacks = mkOption { check-further-callbacks = mkOption {
type = with types; nullOr bool; type = with types; nullOr bool;
default = null; default = null;
description = description = "Whether to check further callbacks after this rule (optional).";
"Whether to check further callbacks after this rule (optional).";
}; };
run = mkOption { run = mkOption {
type = with types; oneOf [ str (listOf str) ]; type =
example = [ "move-node-to-workspace m" "resize-node" ]; with types;
description = oneOf [
"Commands to execute when the conditions match (required)."; str
(listOf str)
];
example = [
"move-node-to-workspace m"
"resize-node"
];
description = "Commands to execute when the conditions match (required).";
}; };
}; };
}); }
);
default = [ ]; default = [ ];
example = [{ example = [
{
"if" = { "if" = {
app-id = "Another.Cool.App"; app-id = "Another.Cool.App";
workspace = "cool-workspace"; workspace = "cool-workspace";
@ -164,14 +192,24 @@ in {
during-aerospace-startup = false; during-aerospace-startup = false;
}; };
check-further-callbacks = false; check-further-callbacks = false;
run = [ "move-node-to-workspace m" "resize-node" ]; run = [
}]; "move-node-to-workspace m"
description = "resize-node"
"Commands to run every time a new window is detected with optional conditions."; ];
}
];
description = "Commands to run every time a new window is detected with optional conditions.";
}; };
workspace-to-monitor-force-assignment = mkOption { workspace-to-monitor-force-assignment = mkOption {
type = with types; type =
nullOr (attrsOf (oneOf [ int str (listOf str) ])); with types;
nullOr (
attrsOf (oneOf [
int
str
(listOf str)
])
);
default = null; default = null;
description = '' description = ''
Map workspaces to specific monitors. Map workspaces to specific monitors.
@ -182,17 +220,18 @@ in {
"2" = "main"; # Main monitor. "2" = "main"; # Main monitor.
"3" = "secondary"; # Secondary monitor (non-main). "3" = "secondary"; # Secondary monitor (non-main).
"4" = "built-in"; # Built-in display. "4" = "built-in"; # Built-in display.
"5" = "5" = "^built-in retina display$"; # Regex for the built-in retina display.
"^built-in retina display$"; # Regex for the built-in retina display. "6" = [
"6" = [ "secondary" "dell" ]; # Match first pattern in the list. "secondary"
"dell"
]; # Match first pattern in the list.
}; };
}; };
on-focus-changed = mkOption { on-focus-changed = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = [ ]; default = [ ];
example = [ "move-mouse monitor-lazy-center" ]; example = [ "move-mouse monitor-lazy-center" ];
description = description = "Commands to run every time focused window or workspace changes.";
"Commands to run every time focused window or workspace changes.";
}; };
on-focused-monitor-changed = mkOption { on-focused-monitor-changed = mkOption {
type = with types; listOf str; type = with types; listOf str;
@ -210,7 +249,10 @@ in {
description = "Commands to run every time workspace changes."; description = "Commands to run every time workspace changes.";
}; };
key-mapping.preset = mkOption { key-mapping.preset = mkOption {
type = types.enum [ "qwerty" "dvorak" ]; type = types.enum [
"qwerty"
"dvorak"
];
default = "qwerty"; default = "qwerty";
description = "Keymapping preset."; description = "Keymapping preset.";
}; };
@ -243,15 +285,14 @@ in {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
assertions = [ assertions = [
(lib.hm.assertions.assertPlatform "programs.aerospace" pkgs (lib.hm.assertions.assertPlatform "programs.aerospace" pkgs lib.platforms.darwin)
lib.platforms.darwin)
]; ];
home = { home = {
packages = lib.mkIf (cfg.package != null) [ cfg.package ]; packages = lib.mkIf (cfg.package != null) [ cfg.package ];
file.".config/aerospace/aerospace.toml".source = file.".config/aerospace/aerospace.toml".source = tomlFormat.generate "aerospace" (
tomlFormat.generate "aerospace" filterNulls (flattenOnWindowDetected cfg.userSettings)
(filterNulls (flattenOnWindowDetected cfg.userSettings)); );
}; };
}; };
} }

View file

@ -1,6 +1,13 @@
{ config, lib, pkgs, ... }: {
let cfg = config.programs.afew; config,
in { lib,
pkgs,
...
}:
let
cfg = config.programs.afew;
in
{
options.programs.afew = { options.programs.afew = {
enable = lib.mkEnableOption "the afew initial tagging script for Notmuch"; enable = lib.mkEnableOption "the afew initial tagging script for Notmuch";

View file

@ -1,8 +1,14 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.programs.alacritty; cfg = config.programs.alacritty;
tomlFormat = pkgs.formats.toml { }; tomlFormat = pkgs.formats.toml { };
in { in
{
options = { options = {
programs.alacritty = { programs.alacritty = {
enable = lib.mkEnableOption "Alacritty"; enable = lib.mkEnableOption "Alacritty";
@ -56,40 +62,45 @@ in {
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
assertions = [{ assertions = [
{
# If using the theme option, ensure that theme exists in the # If using the theme option, ensure that theme exists in the
# alacritty-theme package. # alacritty-theme package.
assertion = let assertion =
let
available = lib.pipe "${pkgs.alacritty-theme}/share/alacritty-theme" [ available = lib.pipe "${pkgs.alacritty-theme}/share/alacritty-theme" [
builtins.readDir builtins.readDir
(lib.filterAttrs (lib.filterAttrs (name: type: type == "regular" && lib.hasSuffix ".toml" name))
(name: type: type == "regular" && lib.hasSuffix ".toml" name))
lib.attrNames lib.attrNames
(lib.map (lib.removeSuffix ".toml")) (lib.map (lib.removeSuffix ".toml"))
]; ];
in cfg.theme == null || (builtins.elem cfg.theme available); in
cfg.theme == null || (builtins.elem cfg.theme available);
message = "The alacritty theme '${cfg.theme}' does not exist."; message = "The alacritty theme '${cfg.theme}' does not exist.";
}]; }
];
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
programs.alacritty.settings = let programs.alacritty.settings =
let
theme = "${pkgs.alacritty-theme}/share/alacritty-theme/${cfg.theme}.toml"; theme = "${pkgs.alacritty-theme}/share/alacritty-theme/${cfg.theme}.toml";
in lib.mkIf (cfg.theme != null) { in
general.import = lib.mkIf (cfg.theme != null) {
lib.mkIf (lib.versionAtLeast cfg.package.version "0.14") [ theme ]; general.import = lib.mkIf (lib.versionAtLeast cfg.package.version "0.14") [ theme ];
import = lib.mkIf (lib.versionOlder cfg.package.version "0.14") [ theme ]; import = lib.mkIf (lib.versionOlder cfg.package.version "0.14") [ theme ];
}; };
xdg.configFile."alacritty/alacritty.toml" = lib.mkIf (cfg.settings != { }) { xdg.configFile."alacritty/alacritty.toml" = lib.mkIf (cfg.settings != { }) {
source = (tomlFormat.generate "alacritty.toml" cfg.settings).overrideAttrs source = (tomlFormat.generate "alacritty.toml" cfg.settings).overrideAttrs (
(finalAttrs: prevAttrs: { finalAttrs: prevAttrs: {
buildCommand = lib.concatStringsSep "\n" [ buildCommand = lib.concatStringsSep "\n" [
prevAttrs.buildCommand prevAttrs.buildCommand
# TODO: why is this needed? Is there a better way to retain escape sequences? # TODO: why is this needed? Is there a better way to retain escape sequences?
"substituteInPlace $out --replace-quiet '\\\\' '\\'" "substituteInPlace $out --replace-quiet '\\\\' '\\'"
]; ];
}); }
);
}; };
}; };
} }

View file

@ -1,7 +1,9 @@
pkgs: pkgs:
{ config, lib, ... }: { config, lib, ... }:
let inherit (lib) mkOption types; let
in { inherit (lib) mkOption types;
in
{
options.alot = { options.alot = {
sendMailCommand = mkOption { sendMailCommand = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
@ -16,11 +18,9 @@ in {
type = types.attrsOf types.str; type = types.attrsOf types.str;
default = { default = {
type = "shellcommand"; type = "shellcommand";
command = command = "'${pkgs.notmuch}/bin/notmuch address --format=json --output=recipients date:6M..'";
"'${pkgs.notmuch}/bin/notmuch address --format=json --output=recipients date:6M..'"; regexp =
regexp = "'\\[?{" + '' "'\\[?{" + ''"name": "(?P<name>.*)", "address": "(?P<email>.+)", "name-addr": ".*"'' + "}[,\\]]?'";
"name": "(?P<name>.*)", "address": "(?P<email>.+)", "name-addr": ".*"''
+ "}[,\\]]?'";
shellcommand_external_filtering = "False"; shellcommand_external_filtering = "False";
}; };
example = lib.literalExpression '' example = lib.literalExpression ''
@ -48,9 +48,8 @@ in {
}; };
config = lib.mkIf config.notmuch.enable { config = lib.mkIf config.notmuch.enable {
alot.sendMailCommand = lib.mkOptionDefault (if config.msmtp.enable then alot.sendMailCommand = lib.mkOptionDefault (
"msmtpq --read-envelope-from --read-recipients" if config.msmtp.enable then "msmtpq --read-envelope-from --read-recipients" else null
else );
null);
}; };
} }

View file

@ -1,22 +1,35 @@
# alot config loader is sensitive to leading space ! # alot config loader is sensitive to leading space !
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) inherit (lib)
concatStringsSep mapAttrsToList mkOption optionalAttrs optionalString types; concatStringsSep
mapAttrsToList
mkOption
optionalAttrs
optionalString
types
;
cfg = config.programs.alot; cfg = config.programs.alot;
enabledAccounts = lib.filter (a: a.notmuch.enable) enabledAccounts = lib.filter (a: a.notmuch.enable) (lib.attrValues config.accounts.email.accounts);
(lib.attrValues config.accounts.email.accounts);
# sorted: primary first # sorted: primary first
alotAccounts = lib.sort (a: b: !(a.primary -> b.primary)) enabledAccounts; alotAccounts = lib.sort (a: b: !(a.primary -> b.primary)) enabledAccounts;
boolStr = v: if v then "True" else "False"; boolStr = v: if v then "True" else "False";
mkKeyValue = key: value: mkKeyValue =
let value' = if lib.isBool value then boolStr value else toString value; key: value:
in "${key} = ${value'}"; let
value' = if lib.isBool value then boolStr value else toString value;
in
"${key} = ${value'}";
mk2ndLevelSectionName = name: "[" + name + "]"; mk2ndLevelSectionName = name: "[" + name + "]";
@ -59,47 +72,74 @@ let
}; };
}; };
accountStr = account: accountStr =
account:
let let
inherit (account) inherit (account)
alot maildir name address realName folders aliases gpg signature; alot
in concatStringsSep "\n" ([ "[[${name}]]" ] maildir
++ mapAttrsToList (n: v: n + "=" + v) ({ name
address
realName
folders
aliases
gpg
signature
;
in
concatStringsSep "\n" (
[ "[[${name}]]" ]
++ mapAttrsToList (n: v: n + "=" + v) (
{
address = address; address = address;
realname = realName; realname = realName;
sendmail_command = sendmail_command = optionalString (alot.sendMailCommand != null) alot.sendMailCommand;
optionalString (alot.sendMailCommand != null) alot.sendMailCommand; }
} // optionalAttrs (folders.sent != null) { // optionalAttrs (folders.sent != null) {
sent_box = "maildir" + "://" + maildir.absPath + "/" + folders.sent; sent_box = "maildir" + "://" + maildir.absPath + "/" + folders.sent;
} // optionalAttrs (folders.drafts != null) { }
// optionalAttrs (folders.drafts != null) {
draft_box = "maildir" + "://" + maildir.absPath + "/" + folders.drafts; draft_box = "maildir" + "://" + maildir.absPath + "/" + folders.drafts;
} // optionalAttrs (aliases != [ ]) { }
// optionalAttrs (aliases != [ ]) {
aliases = concatStringsSep "," aliases; aliases = concatStringsSep "," aliases;
} // optionalAttrs (gpg != null) { }
// optionalAttrs (gpg != null) {
gpg_key = gpg.key; gpg_key = gpg.key;
encrypt_by_default = if gpg.encryptByDefault then "all" else "none"; encrypt_by_default = if gpg.encryptByDefault then "all" else "none";
sign_by_default = boolStr gpg.signByDefault; sign_by_default = boolStr gpg.signByDefault;
} // optionalAttrs (signature.showSignature != "none") { }
// optionalAttrs (signature.showSignature != "none") {
signature = pkgs.writeText "signature.txt" signature.text; signature = pkgs.writeText "signature.txt" signature.text;
signature_as_attachment = boolStr (signature.showSignature == "attach"); signature_as_attachment = boolStr (signature.showSignature == "attach");
}) ++ [ alot.extraConfig ] ++ [ "[[[abook]]]" ] }
++ mapAttrsToList (n: v: n + "=" + v) alot.contactCompletion); )
++ [ alot.extraConfig ]
++ [ "[[[abook]]]" ]
++ mapAttrsToList (n: v: n + "=" + v) alot.contactCompletion
);
configFile = let configFile =
bindingsToStr = attrSet: let
concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${v}") attrSet); bindingsToStr = attrSet: concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${v}") attrSet);
in '' in
''
# Generated by Home Manager. # Generated by Home Manager.
# See http://alot.readthedocs.io/en/latest/configuration/config_options.html # See http://alot.readthedocs.io/en/latest/configuration/config_options.html
${lib.generators.toKeyValue { inherit mkKeyValue; } cfg.settings} ${lib.generators.toKeyValue { inherit mkKeyValue; } cfg.settings}
${cfg.extraConfig} ${cfg.extraConfig}
[tags] [tags]
'' + (let ''
submoduleToAttrs = m: + (
lib.filterAttrs (name: v: name != "_module" && v != null) m; let
in lib.generators.toINI { mkSectionName = mk2ndLevelSectionName; } submoduleToAttrs = m: lib.filterAttrs (name: v: name != "_module" && v != null) m;
(lib.mapAttrs (name: x: submoduleToAttrs x) cfg.tags)) + '' in
lib.generators.toINI { mkSectionName = mk2ndLevelSectionName; } (
lib.mapAttrs (name: x: submoduleToAttrs x) cfg.tags
)
)
+ ''
[bindings] [bindings]
${bindingsToStr cfg.bindings.global} ${bindingsToStr cfg.bindings.global}
@ -119,7 +159,8 @@ let
${lib.concatStringsSep "\n\n" (map accountStr alotAccounts)} ${lib.concatStringsSep "\n\n" (map accountStr alotAccounts)}
''; '';
in { in
{
options = { options = {
programs.alot = { programs.alot = {
enable = mkOption { enable = mkOption {
@ -196,9 +237,12 @@ in {
}; };
settings = mkOption { settings = mkOption {
type = with types; type =
let primitive = either (either (either str int) bool) float; with types;
in attrsOf primitive; let
primitive = either (either (either str int) bool) float;
in
attrsOf primitive;
default = { default = {
initial_command = "search tag:inbox AND NOT tag:killed"; initial_command = "search tag:inbox AND NOT tag:killed";
auto_remove_unread = true; auto_remove_unread = true;
@ -237,9 +281,11 @@ in {
xdg.configFile."alot/config".text = configFile; xdg.configFile."alot/config".text = configFile;
xdg.configFile."alot/hooks.py" = lib.mkIf (cfg.hooks != "") { xdg.configFile."alot/hooks.py" = lib.mkIf (cfg.hooks != "") {
text = '' text =
''
# Generated by Home Manager. # Generated by Home Manager.
'' + cfg.hooks; ''
+ cfg.hooks;
}; };
}; };
} }

View file

@ -1,15 +1,25 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.programs.zsh.antidote; cfg = config.programs.zsh.antidote;
zPluginStr = (pluginNames: zPluginStr = (
lib.optionalString (pluginNames != [ ]) "${lib.concatStrings (map (name: '' pluginNames:
lib.optionalString (pluginNames != [ ])
"${lib.concatStrings (
map (name: ''
${name} ${name}
'') pluginNames)}"); '') pluginNames
)}"
);
parseHashId = path: parseHashId = path: lib.elemAt (builtins.match "${builtins.storeDir}/([a-zA-Z0-9]+)-.*" path) 0;
lib.elemAt (builtins.match "${builtins.storeDir}/([a-zA-Z0-9]+)-.*" path) 0; in
in { {
meta.maintainers = [ lib.maintainers.hitsmaxft ]; meta.maintainers = [ lib.maintainers.hitsmaxft ];
options.programs.zsh.antidote = { options.programs.zsh.antidote = {
@ -30,16 +40,17 @@ in {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
programs.zsh.initContent = let programs.zsh.initContent =
let
configFiles = pkgs.runCommand "hm_antidote-files" { } '' configFiles = pkgs.runCommand "hm_antidote-files" { } ''
echo "${zPluginStr cfg.plugins}" > $out echo "${zPluginStr cfg.plugins}" > $out
''; '';
hashId = parseHashId "${configFiles}"; hashId = parseHashId "${configFiles}";
in (lib.mkOrder 550 '' in
(lib.mkOrder 550 ''
## home-manager/antidote begin : ## home-manager/antidote begin :
source ${cfg.package}/share/antidote/antidote.zsh source ${cfg.package}/share/antidote/antidote.zsh
${lib.optionalString cfg.useFriendlyNames ${lib.optionalString cfg.useFriendlyNames "zstyle ':antidote:bundle' use-friendly-names 'yes'"}
"zstyle ':antidote:bundle' use-friendly-names 'yes'"}
bundlefile=${configFiles} bundlefile=${configFiles}
zstyle ':antidote:bundle' file $bundlefile zstyle ':antidote:bundle' file $bundlefile

View file

@ -1,16 +1,20 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.programs.aria2; cfg = config.programs.aria2;
formatLine = n: v: formatLine =
n: v:
let let
formatValue = v: formatValue = v: if builtins.isBool v then (if v then "true" else "false") else toString v;
if builtins.isBool v then in
(if v then "true" else "false") "${n}=${formatValue v}";
else in
toString v; {
in "${n}=${formatValue v}";
in {
meta.maintainers = [ lib.hm.maintainers.justinlovinger ]; meta.maintainers = [ lib.hm.maintainers.justinlovinger ];
options.programs.aria2 = { options.programs.aria2 = {
@ -19,7 +23,14 @@ in {
package = lib.mkPackageOption pkgs "aria2" { nullable = true; }; package = lib.mkPackageOption pkgs "aria2" { nullable = true; };
settings = lib.mkOption { settings = lib.mkOption {
type = with lib.types; attrsOf (oneOf [ bool float int str ]); type =
with lib.types;
attrsOf (oneOf [
bool
float
int
str
]);
default = { }; default = { };
description = '' description = ''
Options to add to {file}`aria2.conf` file. Options to add to {file}`aria2.conf` file.
@ -50,8 +61,10 @@ in {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
xdg.configFile."aria2/aria2.conf".text = lib.concatStringsSep "\n" ([ ] xdg.configFile."aria2/aria2.conf".text = lib.concatStringsSep "\n" (
[ ]
++ lib.mapAttrsToList formatLine cfg.settings ++ lib.mapAttrsToList formatLine cfg.settings
++ lib.optional (cfg.extraConfig != "") cfg.extraConfig); ++ lib.optional (cfg.extraConfig != "") cfg.extraConfig
);
}; };
} }

View file

@ -1,4 +1,5 @@
{ config, lib, ... }: { { config, lib, ... }:
{
options.astroid = { options.astroid = {
enable = lib.mkEnableOption "Astroid"; enable = lib.mkEnableOption "Astroid";
@ -14,7 +15,9 @@
extraConfig = lib.mkOption { extraConfig = lib.mkOption {
type = lib.types.attrsOf lib.types.anything; type = lib.types.attrsOf lib.types.anything;
default = { }; default = { };
example = { select_query = ""; }; example = {
select_query = "";
};
description = '' description = ''
Extra settings to add to this astroid account configuration. Extra settings to add to this astroid account configuration.
''; '';
@ -22,7 +25,8 @@
}; };
config = lib.mkIf config.notmuch.enable { config = lib.mkIf config.notmuch.enable {
astroid.sendMailCommand = lib.mkIf config.msmtp.enable astroid.sendMailCommand = lib.mkIf config.msmtp.enable (
(lib.mkOptionDefault "msmtpq --read-envelope-from --read-recipients"); lib.mkOptionDefault "msmtpq --read-envelope-from --read-recipients"
);
}; };
} }

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkOption types; inherit (lib) mkOption types;
@ -6,12 +11,12 @@ let
jsonFormat = pkgs.formats.json { }; jsonFormat = pkgs.formats.json { };
astroidAccounts = astroidAccounts = lib.filterAttrs (n: v: v.astroid.enable) config.accounts.email.accounts;
lib.filterAttrs (n: v: v.astroid.enable) config.accounts.email.accounts;
boolOpt = b: if b then "true" else "false"; boolOpt = b: if b then "true" else "false";
accountAttr = account: accountAttr =
account:
with account; with account;
{ {
email = address; email = address;
@ -23,33 +28,38 @@ let
save_sent = "true"; save_sent = "true";
save_sent_to = "${maildir.absPath}/${folders.sent}/cur/"; save_sent_to = "${maildir.absPath}/${folders.sent}/cur/";
select_query = ""; select_query = "";
} // lib.optionalAttrs (signature.showSignature != "none") { }
// lib.optionalAttrs (signature.showSignature != "none") {
signature_attach = boolOpt (signature.showSignature == "attach"); signature_attach = boolOpt (signature.showSignature == "attach");
signature_default_on = boolOpt (signature.showSignature != "none"); signature_default_on = boolOpt (signature.showSignature != "none");
signature_file = pkgs.writeText "signature.txt" signature.text; signature_file = pkgs.writeText "signature.txt" signature.text;
signature_file_markdown = "false"; signature_file_markdown = "false";
signature_separate = "true"; # prepends '--\n' to the signature signature_separate = "true"; # prepends '--\n' to the signature
} // lib.optionalAttrs (gpg != null) { }
// lib.optionalAttrs (gpg != null) {
always_gpg_sign = boolOpt gpg.signByDefault; always_gpg_sign = boolOpt gpg.signByDefault;
gpgkey = gpg.key; gpgkey = gpg.key;
} // astroid.extraConfig; }
// astroid.extraConfig;
# See https://github.com/astroidmail/astroid/wiki/Configuration-Reference # See https://github.com/astroidmail/astroid/wiki/Configuration-Reference
finalConfig = let finalConfig =
let
template = lib.importJSON ./astroid-config-template.json; template = lib.importJSON ./astroid-config-template.json;
astroidConfig = lib.foldl' lib.recursiveUpdate template [ astroidConfig = lib.foldl' lib.recursiveUpdate template [
{ {
astroid.notmuch_config = astroid.notmuch_config = "${config.xdg.configHome}/notmuch/default/config";
"${config.xdg.configHome}/notmuch/default/config";
accounts = lib.mapAttrs (n: accountAttr) astroidAccounts; accounts = lib.mapAttrs (n: accountAttr) astroidAccounts;
crypto.gpg.path = "${pkgs.gnupg}/bin/gpg"; crypto.gpg.path = "${pkgs.gnupg}/bin/gpg";
} }
cfg.extraConfig cfg.extraConfig
cfg.externalEditor cfg.externalEditor
]; ];
in astroidConfig; in
astroidConfig;
in { in
{
options = { options = {
programs.astroid = { programs.astroid = {
enable = lib.mkEnableOption "Astroid"; enable = lib.mkEnableOption "Astroid";
@ -69,15 +79,15 @@ in {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
# Converts it into JSON that can be merged into the configuration. # Converts it into JSON that can be merged into the configuration.
apply = cmd: apply =
cmd:
lib.optionalAttrs (cmd != null) { lib.optionalAttrs (cmd != null) {
editor = { editor = {
"external_editor" = "true"; "external_editor" = "true";
"cmd" = cmd; "cmd" = cmd;
}; };
}; };
example = example = "nvim-qt -- -c 'set ft=mail' '+set fileencoding=utf-8' '+set ff=unix' '+set enc=utf-8' '+set fo+=w' %1";
"nvim-qt -- -c 'set ft=mail' '+set fileencoding=utf-8' '+set ff=unix' '+set enc=utf-8' '+set fo+=w' %1";
description = '' description = ''
You can use the following variables: You can use the following variables:
@ -117,8 +127,7 @@ in {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
xdg.configFile."astroid/config".source = xdg.configFile."astroid/config".source = jsonFormat.generate "astroid-config" finalConfig;
jsonFormat.generate "astroid-config" finalConfig;
xdg.configFile."astroid/poll.sh" = lib.mkIf (cfg.pollScript != "") { xdg.configFile."astroid/poll.sh" = lib.mkIf (cfg.pollScript != "") {
executable = true; executable = true;

View file

@ -1,4 +1,9 @@
{ config, pkgs, lib, ... }: {
config,
pkgs,
lib,
...
}:
let let
cfg = config.programs.atuin; cfg = config.programs.atuin;
daemonCfg = cfg.daemon; daemonCfg = cfg.daemon;
@ -7,8 +12,12 @@ let
inherit (lib) mkIf mkOption types; inherit (lib) mkIf mkOption types;
inherit (pkgs.stdenv) isLinux isDarwin; inherit (pkgs.stdenv) isLinux isDarwin;
in { in
meta.maintainers = with lib.maintainers; [ hawkw water-sucks ]; {
meta.maintainers = with lib.maintainers; [
hawkw
water-sucks
];
options.programs.atuin = { options.programs.atuin = {
enable = lib.mkEnableOption "atuin"; enable = lib.mkEnableOption "atuin";
@ -17,18 +26,15 @@ in {
enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { enableBashIntegration = lib.hm.shell.mkBashIntegrationOption {
inherit config; inherit config;
extraDescription = extraDescription = "If enabled, this will bind `ctrl-r` to open the Atuin history.";
"If enabled, this will bind `ctrl-r` to open the Atuin history.";
}; };
enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { enableFishIntegration = lib.hm.shell.mkFishIntegrationOption {
inherit config; inherit config;
extraDescription = extraDescription = "If enabled, this will bind the up-arrow key to open the Atuin history.";
"If enabled, this will bind the up-arrow key to open the Atuin history.";
}; };
enableNushellIntegration = enableNushellIntegration = lib.hm.shell.mkNushellIntegrationOption { inherit config; };
lib.hm.shell.mkNushellIntegrationOption { inherit config; };
enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { enableZshIntegration = lib.hm.shell.mkZshIntegrationOption {
inherit config; inherit config;
@ -41,21 +47,30 @@ in {
flags = mkOption { flags = mkOption {
default = [ ]; default = [ ];
type = types.listOf types.str; type = types.listOf types.str;
example = [ "--disable-up-arrow" "--disable-ctrl-r" ]; example = [
"--disable-up-arrow"
"--disable-ctrl-r"
];
description = '' description = ''
Flags to append to the shell hook. Flags to append to the shell hook.
''; '';
}; };
settings = mkOption { settings = mkOption {
type = with types; type =
with types;
let let
prim = oneOf [ bool int str ]; prim = oneOf [
bool
int
str
];
primOrPrimAttrs = either prim (attrsOf prim); primOrPrimAttrs = either prim (attrsOf prim);
entry = either prim (listOf primOrPrimAttrs); entry = either prim (listOf primOrPrimAttrs);
entryOrAttrsOf = t: either entry (attrsOf t); entryOrAttrsOf = t: either entry (attrsOf t);
entries = entryOrAttrsOf (entryOrAttrsOf entry); entries = entryOrAttrsOf (entryOrAttrsOf entry);
in attrsOf entries // { description = "Atuin configuration"; }; in
attrsOf entries // { description = "Atuin configuration"; };
default = { }; default = { };
example = lib.literalExpression '' example = lib.literalExpression ''
{ {
@ -79,8 +94,15 @@ in {
logLevel = mkOption { logLevel = mkOption {
default = null; default = null;
type = type = types.nullOr (
types.nullOr (types.enum [ "trace" "debug" "info" "warn" "error" ]); types.enum [
"trace"
"debug"
"info"
"warn"
"error"
]
);
description = '' description = ''
Verbosity of Atuin daemon logging. Verbosity of Atuin daemon logging.
''; '';
@ -88,8 +110,12 @@ in {
}; };
}; };
config = let flagsStr = lib.escapeShellArgs cfg.flags; config =
in mkIf cfg.enable (lib.mkMerge [ let
flagsStr = lib.escapeShellArgs cfg.flags;
in
mkIf cfg.enable (
lib.mkMerge [
{ {
# Always add the configured `atuin` package. # Always add the configured `atuin` package.
home.packages = [ cfg.package ]; home.packages = [ cfg.package ];
@ -119,9 +145,11 @@ in {
programs.nushell = mkIf cfg.enableNushellIntegration { programs.nushell = mkIf cfg.enableNushellIntegration {
extraConfig = '' extraConfig = ''
source ${ source ${
pkgs.runCommand "atuin-nushell-config.nu" { pkgs.runCommand "atuin-nushell-config.nu"
{
nativeBuildInputs = [ pkgs.writableTmpDirAsHomeHook ]; nativeBuildInputs = [ pkgs.writableTmpDirAsHomeHook ];
} '' }
''
${lib.getExe cfg.package} init nu ${flagsStr} >> "$out" ${lib.getExe cfg.package} init nu ${flagsStr} >> "$out"
'' ''
} }
@ -129,7 +157,8 @@ in {
}; };
} }
(mkIf daemonCfg.enable (lib.mkMerge [ (mkIf daemonCfg.enable (
lib.mkMerge [
{ {
assertions = [ assertions = [
{ {
@ -140,15 +169,22 @@ in {
} }
{ {
assertion = isLinux || isDarwin; assertion = isLinux || isDarwin;
message = message = "The Atuin daemon can only be configured on either Linux or macOS.";
"The Atuin daemon can only be configured on either Linux or macOS.";
} }
]; ];
programs.atuin.settings = { daemon = { enabled = true; }; }; programs.atuin.settings = {
daemon = {
enabled = true;
};
};
} }
(mkIf isLinux { (mkIf isLinux {
programs.atuin.settings = { daemon = { systemd_socket = true; }; }; programs.atuin.settings = {
daemon = {
systemd_socket = true;
};
};
systemd.user.services.atuin-daemon = { systemd.user.services.atuin-daemon = {
Unit = { Unit = {
@ -161,22 +197,24 @@ in {
}; };
Service = { Service = {
ExecStart = "${lib.getExe cfg.package} daemon"; ExecStart = "${lib.getExe cfg.package} daemon";
Environment = lib.optionals (daemonCfg.logLevel != null) Environment = lib.optionals (daemonCfg.logLevel != null) [ "ATUIN_LOG=${daemonCfg.logLevel}" ];
[ "ATUIN_LOG=${daemonCfg.logLevel}" ];
Restart = "on-failure"; Restart = "on-failure";
RestartSteps = 3; RestartSteps = 3;
RestartMaxDelaySec = 6; RestartMaxDelaySec = 6;
}; };
}; };
systemd.user.sockets.atuin-daemon = let systemd.user.sockets.atuin-daemon =
socket_dir = if lib.versionAtLeast cfg.package.version "18.4.0" then let
"%t" socket_dir = if lib.versionAtLeast cfg.package.version "18.4.0" then "%t" else "%D/atuin";
else in
"%D/atuin"; {
in { Unit = {
Unit = { Description = "Atuin daemon socket"; }; Description = "Atuin daemon socket";
Install = { WantedBy = [ "sockets.target" ]; }; };
Install = {
WantedBy = [ "sockets.target" ];
};
Socket = { Socket = {
ListenStream = "${socket_dir}/atuin.sock"; ListenStream = "${socket_dir}/atuin.sock";
SocketMode = "0600"; SocketMode = "0600";
@ -187,17 +225,18 @@ in {
(mkIf isDarwin { (mkIf isDarwin {
programs.atuin.settings = { programs.atuin.settings = {
daemon = { daemon = {
socket_path = socket_path = lib.mkDefault "${config.xdg.dataHome}/atuin/daemon.sock";
lib.mkDefault "${config.xdg.dataHome}/atuin/daemon.sock";
}; };
}; };
launchd.agents.atuin-daemon = { launchd.agents.atuin-daemon = {
enable = true; enable = true;
config = { config = {
ProgramArguments = [ "${lib.getExe cfg.package}" "daemon" ]; ProgramArguments = [
EnvironmentVariables = "${lib.getExe cfg.package}"
lib.optionalAttrs (daemonCfg.logLevel != null) { "daemon"
];
EnvironmentVariables = lib.optionalAttrs (daemonCfg.logLevel != null) {
ATUIN_LOG = daemonCfg.logLevel; ATUIN_LOG = daemonCfg.logLevel;
}; };
KeepAlive = { KeepAlive = {
@ -208,6 +247,8 @@ in {
}; };
}; };
}) })
])) ]
]); ))
]
);
} }

View file

@ -1,9 +1,15 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.programs.autojump; cfg = config.programs.autojump;
inherit (lib) mkIf; inherit (lib) mkIf;
in { in
{
meta.maintainers = [ lib.maintainers.evanjs ]; meta.maintainers = [ lib.maintainers.evanjs ];
options.programs.autojump = { options.programs.autojump = {
@ -11,22 +17,21 @@ in {
package = lib.mkPackageOption pkgs "autojump" { }; package = lib.mkPackageOption pkgs "autojump" { };
enableBashIntegration = enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { inherit config; };
lib.hm.shell.mkBashIntegrationOption { inherit config; };
enableFishIntegration = enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { inherit config; };
lib.hm.shell.mkFishIntegrationOption { inherit config; };
enableZshIntegration = enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; };
lib.hm.shell.mkZshIntegrationOption { inherit config; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
home.packages = [ cfg.package ]; home.packages = [ cfg.package ];
programs.bash.initExtra = mkIf cfg.enableBashIntegration (lib.mkBefore '' programs.bash.initExtra = mkIf cfg.enableBashIntegration (
lib.mkBefore ''
. ${cfg.package}/share/autojump/autojump.bash . ${cfg.package}/share/autojump/autojump.bash
''); ''
);
programs.zsh.initContent = mkIf cfg.enableZshIntegration '' programs.zsh.initContent = mkIf cfg.enableZshIntegration ''
. ${cfg.package}/share/autojump/autojump.zsh . ${cfg.package}/share/autojump/autojump.zsh

View file

@ -1,25 +1,49 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) inherit (lib)
literalExpression listToAttrs mapAttrs' mapAttrsToList mkIf mkOption literalExpression
optional types; listToAttrs
mapAttrs'
mapAttrsToList
mkIf
mkOption
optional
types
;
cfg = config.programs.autorandr; cfg = config.programs.autorandr;
matrixOf = n: m: elemType: matrixOf =
n: m: elemType:
lib.mkOptionType rec { lib.mkOptionType rec {
name = "matrixOf"; name = "matrixOf";
description = description = "${toString n}×${toString m} matrix of ${elemType.description}s";
"${toString n}×${toString m} matrix of ${elemType.description}s"; check =
check = xss: xss:
let listOfSize = l: xs: lib.isList xs && lib.length xs == l; let
in listOfSize n xss listOfSize = l: xs: lib.isList xs && lib.length xs == l;
&& lib.all (xs: listOfSize m xs && lib.all elemType.check xs) xss; in
listOfSize n xss && lib.all (xs: listOfSize m xs && lib.all elemType.check xs) xss;
merge = lib.mergeOneOption; merge = lib.mergeOneOption;
getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "*" "*" ]); getSubOptions =
prefix:
elemType.getSubOptions (
prefix
++ [
"*"
"*"
]
);
getSubModules = elemType.getSubModules; getSubModules = elemType.getSubModules;
substSubModules = mod: matrixOf n m (elemType.substSubModules mod); substSubModules = mod: matrixOf n m (elemType.substSubModules mod);
functor = (lib.defaultFunctor name) // { wrapped = elemType; }; functor = (lib.defaultFunctor name) // {
wrapped = elemType;
};
}; };
profileModule = types.submodule { profileModule = types.submodule {
@ -97,7 +121,14 @@ let
}; };
rotate = mkOption { rotate = mkOption {
type = types.nullOr (types.enum [ "normal" "left" "right" "inverted" ]); type = types.nullOr (
types.enum [
"normal"
"left"
"right"
"inverted"
]
);
description = "Output rotate configuration."; description = "Output rotate configuration.";
default = null; default = null;
example = "left"; example = "left";
@ -128,10 +159,14 @@ let
}; };
scale = mkOption { scale = mkOption {
type = types.nullOr (types.submodule { type = types.nullOr (
types.submodule {
options = { options = {
method = mkOption { method = mkOption {
type = types.enum [ "factor" "pixel" ]; type = types.enum [
"factor"
"pixel"
];
description = "Output scaling method."; description = "Output scaling method.";
default = "factor"; default = "factor";
example = "pixel"; example = "pixel";
@ -147,7 +182,8 @@ let
description = "Vertical scaling factor/pixels."; description = "Vertical scaling factor/pixels.";
}; };
}; };
}); }
);
description = '' description = ''
Output scale configuration. Output scale configuration.
@ -172,7 +208,12 @@ let
}; };
filter = mkOption { filter = mkOption {
type = types.nullOr (types.enum [ "bilinear" "nearest" ]); type = types.nullOr (
types.enum [
"bilinear"
"nearest"
]
);
description = "Interpolation method to be used for scaling the output."; description = "Interpolation method to be used for scaling the output.";
default = null; default = null;
example = "nearest"; example = "nearest";
@ -242,30 +283,35 @@ let
}; };
}; };
hookToFile = folder: name: hook: hookToFile =
folder: name: hook:
lib.nameValuePair "autorandr/${folder}/${name}" { lib.nameValuePair "autorandr/${folder}/${name}" {
source = "${pkgs.writeShellScriptBin "hook" hook}/bin/hook"; source = "${pkgs.writeShellScriptBin "hook" hook}/bin/hook";
}; };
profileToFiles = name: profile: profileToFiles =
let inherit (profile) hooks; name: profile:
in lib.mkMerge [ let
inherit (profile) hooks;
in
lib.mkMerge [
{ {
"autorandr/${name}/setup".text = lib.concatStringsSep "\n" "autorandr/${name}/setup".text = lib.concatStringsSep "\n" (
(mapAttrsToList fingerprintToString profile.fingerprint); mapAttrsToList fingerprintToString profile.fingerprint
"autorandr/${name}/config".text = lib.concatStringsSep "\n" );
(mapAttrsToList configToString profile.config); "autorandr/${name}/config".text = lib.concatStringsSep "\n" (
mapAttrsToList configToString profile.config
);
} }
(mkIf (hooks.postswitch != "") (mkIf (hooks.postswitch != "") (listToAttrs [ (hookToFile name "postswitch" hooks.postswitch) ]))
(listToAttrs [ (hookToFile name "postswitch" hooks.postswitch) ])) (mkIf (hooks.preswitch != "") (listToAttrs [ (hookToFile name "preswitch" hooks.preswitch) ]))
(mkIf (hooks.preswitch != "") (mkIf (hooks.predetect != "") (listToAttrs [ (hookToFile name "predetect" hooks.predetect) ]))
(listToAttrs [ (hookToFile name "preswitch" hooks.preswitch) ]))
(mkIf (hooks.predetect != "")
(listToAttrs [ (hookToFile name "predetect" hooks.predetect) ]))
]; ];
fingerprintToString = name: edid: "${name} ${edid}"; fingerprintToString = name: edid: "${name} ${edid}";
configToString = name: config: configToString =
name: config:
if config.enable then if config.enable then
lib.concatStringsSep "\n" ([ "output ${name}" ] lib.concatStringsSep "\n" (
[ "output ${name}" ]
++ optional (config.position != "") "pos ${config.position}" ++ optional (config.position != "") "pos ${config.position}"
++ optional (config.crtc != null) "crtc ${toString config.crtc}" ++ optional (config.crtc != null) "crtc ${toString config.crtc}"
++ optional config.primary "primary" ++ optional config.primary "primary"
@ -275,18 +321,23 @@ let
++ optional (config.rate != "") "rate ${config.rate}" ++ optional (config.rate != "") "rate ${config.rate}"
++ optional (config.rotate != null) "rotate ${config.rotate}" ++ optional (config.rotate != null) "rotate ${config.rotate}"
++ optional (config.filter != null) "filter ${config.filter}" ++ optional (config.filter != null) "filter ${config.filter}"
++ optional (config.transform != null) ("transform " ++ optional (config.transform != null) (
+ lib.concatMapStringsSep "," toString (lib.flatten config.transform)) "transform " + lib.concatMapStringsSep "," toString (lib.flatten config.transform)
++ optional (config.scale != null) )
((if config.scale.method == "factor" then "scale" else "scale-from") ++ optional (config.scale != null) (
+ " ${toString config.scale.x}x${toString config.scale.y}") (if config.scale.method == "factor" then "scale" else "scale-from")
++ optional (config.extraConfig != "") config.extraConfig) + " ${toString config.scale.x}x${toString config.scale.y}"
else '' )
++ optional (config.extraConfig != "") config.extraConfig
)
else
''
output ${name} output ${name}
off off
''; '';
in { in
{
options = { options = {
programs.autorandr = { programs.autorandr = {
enable = lib.mkEnableOption "Autorandr"; enable = lib.mkEnableOption "Autorandr";
@ -358,7 +409,9 @@ in {
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
assertions = lib.flatten (mapAttrsToList (profile: assertions = lib.flatten (
mapAttrsToList (
profile:
{ config, ... }: { config, ... }:
mapAttrsToList (output: opts: { mapAttrsToList (output: opts: {
assertion = opts.scale == null || opts.transform == null; assertion = opts.scale == null || opts.transform == null;
@ -366,7 +419,9 @@ in {
Cannot use the profile output options 'scale' and 'transform' simultaneously. Cannot use the profile output options 'scale' and 'transform' simultaneously.
Check configuration for: programs.autorandr.profiles.${profile}.config.${output} Check configuration for: programs.autorandr.profiles.${profile}.config.${output}
''; '';
}) config) cfg.profiles); }) config
) cfg.profiles
);
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];

View file

@ -1,10 +1,16 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.programs.awscli; cfg = config.programs.awscli;
iniFormat = pkgs.formats.ini { }; iniFormat = pkgs.formats.ini { };
in { in
{
meta.maintainers = [ lib.maintainers.anthonyroussel ]; meta.maintainers = [ lib.maintainers.anthonyroussel ];
options.programs.awscli = { options.programs.awscli = {
@ -55,16 +61,12 @@ in {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
home.file."${config.home.homeDirectory}/.aws/config" = home.file."${config.home.homeDirectory}/.aws/config" = lib.mkIf (cfg.settings != { }) {
lib.mkIf (cfg.settings != { }) { source = iniFormat.generate "aws-config-${config.home.username}" cfg.settings;
source =
iniFormat.generate "aws-config-${config.home.username}" cfg.settings;
}; };
home.file."${config.home.homeDirectory}/.aws/credentials" = home.file."${config.home.homeDirectory}/.aws/credentials" = lib.mkIf (cfg.credentials != { }) {
lib.mkIf (cfg.credentials != { }) { source = iniFormat.generate "aws-credentials-${config.home.username}" cfg.credentials;
source = iniFormat.generate "aws-credentials-${config.home.username}"
cfg.credentials;
}; };
}; };
} }

View file

@ -1,16 +1,23 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.programs.bacon; cfg = config.programs.bacon;
settingsFormat = pkgs.formats.toml { }; settingsFormat = pkgs.formats.toml { };
configDir = if pkgs.stdenv.isDarwin then configDir =
if pkgs.stdenv.isDarwin then
"Library/Application Support/org.dystroy.bacon" "Library/Application Support/org.dystroy.bacon"
else else
"${config.xdg.configHome}/bacon"; "${config.xdg.configHome}/bacon";
in { in
{
meta.maintainers = [ lib.hm.maintainers.shimunn ]; meta.maintainers = [ lib.hm.maintainers.shimunn ];
options.programs.bacon = { options.programs.bacon = {
@ -23,7 +30,13 @@ in {
default = { }; default = { };
example = { example = {
jobs.default = { jobs.default = {
command = [ "cargo" "build" "--all-features" "--color" "always" ]; command = [
"cargo"
"build"
"--all-features"
"--color"
"always"
];
need_stdout = true; need_stdout = true;
}; };
}; };

View file

@ -1,10 +1,21 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkIf mkOption optionalAttrs types; inherit (lib)
mkIf
mkOption
optionalAttrs
types
;
cfg = config.programs.bash; cfg = config.programs.bash;
writeBashScript = name: text: writeBashScript =
name: text:
pkgs.writeTextFile { pkgs.writeTextFile {
inherit name text; inherit name text;
checkPhase = '' checkPhase = ''
@ -12,15 +23,19 @@ let
''; '';
}; };
in { in
{
meta.maintainers = [ lib.maintainers.rycee ]; meta.maintainers = [ lib.maintainers.rycee ];
imports = [ imports = [
(lib.mkRenamedOptionModule [ "programs" "bash" "enableAutojump" ] [ (lib.mkRenamedOptionModule
[ "programs" "bash" "enableAutojump" ]
[
"programs" "programs"
"autojump" "autojump"
"enable" "enable"
]) ]
)
]; ];
options = { options = {
@ -70,8 +85,14 @@ in {
}; };
historyControl = mkOption { historyControl = mkOption {
type = types.listOf type = types.listOf (
(types.enum [ "erasedups" "ignoredups" "ignorespace" "ignoreboth" ]); types.enum [
"erasedups"
"ignoredups"
"ignorespace"
"ignoreboth"
]
);
default = [ ]; default = [ ];
description = "Controlling how commands are saved on the history list."; description = "Controlling how commands are saved on the history list.";
}; };
@ -79,9 +100,12 @@ in {
historyIgnore = mkOption { historyIgnore = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ ]; default = [ ];
example = [ "ls" "cd" "exit" ]; example = [
description = "ls"
"List of commands that should not be saved to the history list."; "cd"
"exit"
];
description = "List of commands that should not be saved to the history list.";
}; };
shellOptions = mkOption { shellOptions = mkOption {
@ -101,7 +125,10 @@ in {
# Warn if closing shell with running jobs. # Warn if closing shell with running jobs.
"checkjobs" "checkjobs"
]; ];
example = [ "extglob" "-cdspell" ]; example = [
"extglob"
"-cdspell"
];
description = '' description = ''
Shell options to set. Prefix an option with Shell options to set. Prefix an option with
"`-`" to unset. "`-`" to unset.
@ -111,7 +138,9 @@ in {
sessionVariables = mkOption { sessionVariables = mkOption {
default = { }; default = { };
type = types.attrs; type = types.attrs;
example = { MAILCHECK = 30; }; example = {
MAILCHECK = 30;
};
description = '' description = ''
Environment variables that will be set for the Bash session. Environment variables that will be set for the Bash session.
''; '';
@ -170,33 +199,44 @@ in {
}; };
}; };
config = let config =
aliasesStr = lib.concatStringsSep "\n" let
(lib.mapAttrsToList (k: v: "alias ${k}=${lib.escapeShellArg v}") aliasesStr = lib.concatStringsSep "\n" (
cfg.shellAliases); lib.mapAttrsToList (k: v: "alias ${k}=${lib.escapeShellArg v}") cfg.shellAliases
);
shoptsStr = let switch = v: if lib.hasPrefix "-" v then "-u" else "-s"; shoptsStr =
in lib.concatStringsSep "\n" let
(map (v: "shopt ${switch v} ${lib.removePrefix "-" v}") cfg.shellOptions); switch = v: if lib.hasPrefix "-" v then "-u" else "-s";
in
lib.concatStringsSep "\n" (map (v: "shopt ${switch v} ${lib.removePrefix "-" v}") cfg.shellOptions);
sessionVarsStr = config.lib.shell.exportAll cfg.sessionVariables; sessionVarsStr = config.lib.shell.exportAll cfg.sessionVariables;
historyControlStr = (lib.concatStringsSep "\n" historyControlStr = (
(lib.mapAttrsToList (n: v: "${n}=${v}") lib.concatStringsSep "\n" (
(optionalAttrs (cfg.historyFileSize != null) { lib.mapAttrsToList (n: v: "${n}=${v}") (
optionalAttrs (cfg.historyFileSize != null) {
HISTFILESIZE = toString cfg.historyFileSize; HISTFILESIZE = toString cfg.historyFileSize;
} // optionalAttrs (cfg.historySize != null) { }
// optionalAttrs (cfg.historySize != null) {
HISTSIZE = toString cfg.historySize; HISTSIZE = toString cfg.historySize;
} // optionalAttrs (cfg.historyFile != null) { }
// optionalAttrs (cfg.historyFile != null) {
HISTFILE = ''"${cfg.historyFile}"''; HISTFILE = ''"${cfg.historyFile}"'';
} // optionalAttrs (cfg.historyControl != [ ]) { }
// optionalAttrs (cfg.historyControl != [ ]) {
HISTCONTROL = lib.concatStringsSep ":" cfg.historyControl; HISTCONTROL = lib.concatStringsSep ":" cfg.historyControl;
} // optionalAttrs (cfg.historyIgnore != [ ]) { }
HISTIGNORE = // optionalAttrs (cfg.historyIgnore != [ ]) {
lib.escapeShellArg (lib.concatStringsSep ":" cfg.historyIgnore); HISTIGNORE = lib.escapeShellArg (lib.concatStringsSep ":" cfg.historyIgnore);
}) ++ lib.optional (cfg.historyFile != null) }
''mkdir -p "$(dirname "$HISTFILE")"'')); )
in mkIf cfg.enable { ++ lib.optional (cfg.historyFile != null) ''mkdir -p "$(dirname "$HISTFILE")"''
)
);
in
mkIf cfg.enable {
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
home.file.".bash_profile".source = writeBashScript "bash_profile" '' home.file.".bash_profile".source = writeBashScript "bash_profile" ''
@ -210,11 +250,13 @@ in {
# If completion is enabled then make sure it is sourced very early. This # If completion is enabled then make sure it is sourced very early. This
# is to avoid problems if any other initialization code attempts to set up # is to avoid problems if any other initialization code attempts to set up
# completion. # completion.
programs.bash.initExtra = mkIf cfg.enableCompletion (lib.mkOrder 100 '' programs.bash.initExtra = mkIf cfg.enableCompletion (
lib.mkOrder 100 ''
if [[ ! -v BASH_COMPLETION_VERSINFO ]]; then if [[ ! -v BASH_COMPLETION_VERSINFO ]]; then
. "${pkgs.bash-completion}/etc/profile.d/bash_completion.sh" . "${pkgs.bash-completion}/etc/profile.d/bash_completion.sh"
fi fi
''); ''
);
home.file.".profile".source = writeBashScript "profile" '' home.file.".profile".source = writeBashScript "profile" ''
. "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh" . "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh"

View file

@ -1,6 +1,13 @@
{ config, lib, pkgs, ... }: {
let cfg = config.programs.bashmount; config,
in { lib,
pkgs,
...
}:
let
cfg = config.programs.bashmount;
in
{
meta.maintainers = [ lib.maintainers.AndersonTorres ]; meta.maintainers = [ lib.maintainers.AndersonTorres ];
options.programs.bashmount = { options.programs.bashmount = {
@ -24,7 +31,6 @@ in {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
xdg.configFile."bashmount/config" = xdg.configFile."bashmount/config" = lib.mkIf (cfg.extraConfig != "") { text = cfg.extraConfig; };
lib.mkIf (cfg.extraConfig != "") { text = cfg.extraConfig; };
}; };
} }

View file

@ -1,10 +1,22 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) literalExpression mkEnableOption mkOption mkIf types; inherit (lib)
literalExpression
mkEnableOption
mkOption
mkIf
types
;
cfg = config.programs.bat; cfg = config.programs.bat;
toConfigFile = attrs: toConfigFile =
attrs:
let let
inherit (builtins) isBool attrNames; inherit (builtins) isBool attrNames;
nonBoolFlags = lib.filterAttrs (_: v: !(isBool v)) attrs; nonBoolFlags = lib.filterAttrs (_: v: !(isBool v)) attrs;
@ -17,20 +29,31 @@ let
switches = lib.concatMapStrings (k: '' switches = lib.concatMapStrings (k: ''
--${k} --${k}
'') (attrNames enabledBoolFlags); '') (attrNames enabledBoolFlags);
in keyValuePairs + switches; in
in { keyValuePairs + switches;
in
{
meta.maintainers = with lib.maintainers; [ khaneliman ]; meta.maintainers = with lib.maintainers; [ khaneliman ];
options.programs.bat = { options.programs.bat = {
enable = mkEnableOption "bat, a cat clone with wings"; enable = mkEnableOption "bat, a cat clone with wings";
config = mkOption { config = mkOption {
type = with types; attrsOf (oneOf [ str (listOf str) bool ]); type =
with types;
attrsOf (oneOf [
str
(listOf str)
bool
]);
default = { }; default = { };
example = { example = {
theme = "TwoDark"; theme = "TwoDark";
pager = "less -FR"; pager = "less -FR";
map-syntax = [ "*.jenkinsfile:Groovy" "*.props:Java Properties" ]; map-syntax = [
"*.jenkinsfile:Groovy"
"*.props:Java Properties"
];
}; };
description = '' description = ''
Bat configuration. Bat configuration.
@ -40,8 +63,7 @@ in {
extraPackages = mkOption { extraPackages = mkOption {
type = types.listOf types.package; type = types.listOf types.package;
default = [ ]; default = [ ];
example = literalExpression example = literalExpression "with pkgs.bat-extras; [ batdiff batman batgrep batwatch ];";
"with pkgs.bat-extras; [ batdiff batman batgrep batwatch ];";
description = '' description = ''
Additional bat packages to install. Additional bat packages to install.
''; '';
@ -50,7 +72,9 @@ in {
package = lib.mkPackageOption pkgs "bat" { }; package = lib.mkPackageOption pkgs "bat" { };
themes = mkOption { themes = mkOption {
type = types.attrsOf (types.either types.lines (types.submodule { type = types.attrsOf (
types.either types.lines (
types.submodule {
options = { options = {
src = mkOption { src = mkOption {
type = types.path; type = types.path;
@ -60,11 +84,12 @@ in {
file = mkOption { file = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
description = description = "Subpath of the theme file within the source, if needed.";
"Subpath of the theme file within the source, if needed.";
}; };
}; };
})); }
)
);
default = { }; default = { };
example = literalExpression '' example = literalExpression ''
{ {
@ -85,7 +110,9 @@ in {
}; };
syntaxes = mkOption { syntaxes = mkOption {
type = types.attrsOf (types.either types.lines (types.submodule { type = types.attrsOf (
types.either types.lines (
types.submodule {
options = { options = {
src = mkOption { src = mkOption {
type = types.path; type = types.path;
@ -94,11 +121,12 @@ in {
file = mkOption { file = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
description = description = "Subpath of the syntax file within the source, if needed.";
"Subpath of the syntax file within the source, if needed.";
}; };
}; };
})); }
)
);
default = { }; default = { };
example = literalExpression '' example = literalExpression ''
{ {
@ -119,42 +147,62 @@ in {
}; };
}; };
config = mkIf cfg.enable (lib.mkMerge [ config = mkIf cfg.enable (
lib.mkMerge [
(mkIf (lib.any lib.isString (lib.attrValues cfg.themes)) { (mkIf (lib.any lib.isString (lib.attrValues cfg.themes)) {
warnings = ['' warnings = [
''
Using programs.bat.themes as a string option is deprecated and will be Using programs.bat.themes as a string option is deprecated and will be
removed in the future. Please change to using it as an attribute set removed in the future. Please change to using it as an attribute set
instead. instead.
'']; ''
];
}) })
(mkIf (lib.any lib.isString (lib.attrValues cfg.syntaxes)) { (mkIf (lib.any lib.isString (lib.attrValues cfg.syntaxes)) {
warnings = ['' warnings = [
''
Using programs.bat.syntaxes as a string option is deprecated and will be Using programs.bat.syntaxes as a string option is deprecated and will be
removed in the future. Please change to using it as an attribute set removed in the future. Please change to using it as an attribute set
instead. instead.
'']; ''
];
}) })
{ {
home.packages = [ cfg.package ] ++ cfg.extraPackages; home.packages = [ cfg.package ] ++ cfg.extraPackages;
xdg.configFile = lib.mkMerge ([{ xdg.configFile = lib.mkMerge (
"bat/config" = [
mkIf (cfg.config != { }) { text = toConfigFile cfg.config; }; {
}] ++ (lib.flip lib.mapAttrsToList cfg.themes (name: val: { "bat/config" = mkIf (cfg.config != { }) { text = toConfigFile cfg.config; };
"bat/themes/${name}.tmTheme" = if lib.isString val then { }
]
++ (lib.flip lib.mapAttrsToList cfg.themes (
name: val: {
"bat/themes/${name}.tmTheme" =
if lib.isString val then
{
text = val; text = val;
} else { }
source = else
if isNull val.file then "${val.src}" else "${val.src}/${val.file}"; {
source = if isNull val.file then "${val.src}" else "${val.src}/${val.file}";
}; };
})) ++ (lib.flip lib.mapAttrsToList cfg.syntaxes (name: val: { }
"bat/syntaxes/${name}.sublime-syntax" = if lib.isString val then { ))
++ (lib.flip lib.mapAttrsToList cfg.syntaxes (
name: val: {
"bat/syntaxes/${name}.sublime-syntax" =
if lib.isString val then
{
text = val; text = val;
} else { }
source = else
if isNull val.file then "${val.src}" else "${val.src}/${val.file}"; {
source = if isNull val.file then "${val.src}" else "${val.src}/${val.file}";
}; };
}))); }
))
);
# NOTE: run `bat cache --build` in an empty directory to work # NOTE: run `bat cache --build` in an empty directory to work
# around failure when ~/cache exists # around failure when ~/cache exists
@ -168,5 +216,6 @@ in {
) )
''; '';
} }
]); ]
);
} }

View file

@ -1,22 +1,34 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) literalExpression mkIf mkOption types; inherit (lib)
literalExpression
mkIf
mkOption
types
;
cfg = config.programs.beets; cfg = config.programs.beets;
yamlFormat = pkgs.formats.yaml { }; yamlFormat = pkgs.formats.yaml { };
in { in
meta.maintainers = with lib.maintainers; [ rycee Scrumplex ]; {
meta.maintainers = with lib.maintainers; [
rycee
Scrumplex
];
options = { options = {
programs.beets = { programs.beets = {
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = if lib.versionAtLeast config.home.stateVersion "19.03" then default =
false if lib.versionAtLeast config.home.stateVersion "19.03" then false else cfg.settings != { };
else
cfg.settings != { };
defaultText = "false"; defaultText = "false";
description = '' description = ''
Whether to enable the beets music library manager. This Whether to enable the beets music library manager. This
@ -27,8 +39,7 @@ in {
}; };
package = lib.mkPackageOption pkgs "beets" { package = lib.mkPackageOption pkgs "beets" {
example = example = "(pkgs.beets.override { pluginOverrides = { beatport.enable = false; }; })";
"(pkgs.beets.override { pluginOverrides = { beatport.enable = false; }; })";
extraDescription = '' extraDescription = ''
Can be used to specify extensions. Can be used to specify extensions.
''; '';
@ -70,8 +81,7 @@ in {
(mkIf cfg.enable { (mkIf cfg.enable {
home.packages = [ cfg.package ]; home.packages = [ cfg.package ];
xdg.configFile."beets/config.yaml".source = xdg.configFile."beets/config.yaml".source = yamlFormat.generate "beets-config" cfg.settings;
yamlFormat.generate "beets-config" cfg.settings;
}) })
(mkIf (cfg.mpdIntegration.enableStats || cfg.mpdIntegration.enableUpdate) { (mkIf (cfg.mpdIntegration.enableStats || cfg.mpdIntegration.enableUpdate) {

View file

@ -1,6 +1,13 @@
{ config, lib, pkgs, ... }: {
let cfg = config.programs.bemenu; config,
in { lib,
pkgs,
...
}:
let
cfg = config.programs.bemenu;
in
{
meta.maintainers = [ ]; meta.maintainers = [ ];
options.programs.bemenu = { options.programs.bemenu = {
@ -9,7 +16,13 @@ in {
package = lib.mkPackageOption pkgs "bemenu" { nullable = true; }; package = lib.mkPackageOption pkgs "bemenu" { nullable = true; };
settings = lib.mkOption { settings = lib.mkOption {
type = with lib.types; attrsOf (oneOf [ str number bool ]); type =
with lib.types;
attrsOf (oneOf [
str
number
bool
]);
default = { }; default = { };
example = lib.literalExpression '' example = lib.literalExpression ''
{ {
@ -29,15 +42,13 @@ in {
width-factor = 0.3; width-factor = 0.3;
} }
''; '';
description = description = "Configuration options for bemenu. See {manpage}`bemenu(1)`.";
"Configuration options for bemenu. See {manpage}`bemenu(1)`.";
}; };
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
assertions = [ assertions = [
(lib.hm.assertions.assertPlatform "programs.bemenu" pkgs (lib.hm.assertions.assertPlatform "programs.bemenu" pkgs lib.platforms.linux)
lib.platforms.linux)
]; ];
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) literalExpression mkOption types; inherit (lib) literalExpression mkOption types;
@ -6,24 +11,33 @@ let
yamlFormat = pkgs.formats.yaml { }; yamlFormat = pkgs.formats.yaml { };
mkNullableOption = args: mkNullableOption =
lib.mkOption (args // { args:
lib.mkOption (
args
// {
type = lib.types.nullOr args.type; type = lib.types.nullOr args.type;
default = null; default = null;
}); }
);
cleanRepositories = repos: cleanRepositories =
map (repo: repos:
if builtins.isString repo then { map (
repo:
if builtins.isString repo then
{
path = repo; path = repo;
} else }
removeNullValues repo) repos; else
removeNullValues repo
) repos;
mkRetentionOption = frequency: mkRetentionOption =
frequency:
mkNullableOption { mkNullableOption {
type = types.int; type = types.int;
description = description = "Number of ${frequency} archives to keep. Use -1 for no limit.";
"Number of ${frequency} archives to keep. Use -1 for no limit.";
example = 3; example = 3;
}; };
@ -56,7 +70,12 @@ let
consistencyCheckModule = types.submodule { consistencyCheckModule = types.submodule {
options = { options = {
name = mkOption { name = mkOption {
type = types.enum [ "repository" "archives" "data" "extract" ]; type = types.enum [
"repository"
"archives"
"data"
"extract"
];
description = "Name of consistency check to run."; description = "Name of consistency check to run.";
example = "repository"; example = "repository";
}; };
@ -69,10 +88,12 @@ let
}; };
}; };
configModule = types.submodule ({ config, ... }: { configModule = types.submodule (
config.location.extraConfig.exclude_from = { config, ... }:
lib.mkIf config.location.excludeHomeManagerSymlinks {
(lib.mkAfter [ (toString hmExcludeFile) ]); config.location.extraConfig.exclude_from = lib.mkIf config.location.excludeHomeManagerSymlinks (
lib.mkAfter [ (toString hmExcludeFile) ]
);
options = { options = {
location = { location = {
sourceDirectories = mkNullableOption { sourceDirectories = mkNullableOption {
@ -147,8 +168,7 @@ let
encryptionPasscommand = mkNullableOption { encryptionPasscommand = mkNullableOption {
type = types.str; type = types.str;
description = "Command writing the passphrase to standard output."; description = "Command writing the passphrase to standard output.";
example = example = literalExpression ''"''${pkgs.password-store}/bin/pass borg-repo"'';
literalExpression ''"''${pkgs.password-store}/bin/pass borg-repo"'';
}; };
extraConfig = extraConfigOption; extraConfig = extraConfigOption;
}; };
@ -201,14 +221,18 @@ let
extraConfig = extraConfigOption; extraConfig = extraConfigOption;
}; };
output = { extraConfig = extraConfigOption; }; output = {
extraConfig = extraConfigOption;
hooks = { extraConfig = extraConfigOption; };
}; };
});
removeNullValues = attrSet: hooks = {
lib.filterAttrs (key: value: value != null) attrSet; extraConfig = extraConfigOption;
};
};
}
);
removeNullValues = attrSet: lib.filterAttrs (key: value: value != null) attrSet;
hmFiles = builtins.attrValues config.home.file; hmFiles = builtins.attrValues config.home.file;
hmSymlinks = (lib.filter (file: !file.recursive) hmFiles); hmSymlinks = (lib.filter (file: !file.recursive) hmFiles);
@ -218,8 +242,11 @@ let
hmExcludePatterns = lib.concatMapStrings hmExcludePattern hmSymlinks; hmExcludePatterns = lib.concatMapStrings hmExcludePattern hmSymlinks;
hmExcludeFile = pkgs.writeText "hm-symlinks.txt" hmExcludePatterns; hmExcludeFile = pkgs.writeText "hm-symlinks.txt" hmExcludePatterns;
writeConfig = config: writeConfig =
lib.generators.toYAML { } (removeNullValues ({ config:
lib.generators.toYAML { } (
removeNullValues (
{
source_directories = config.location.sourceDirectories; source_directories = config.location.sourceDirectories;
patterns = config.location.patterns; patterns = config.location.patterns;
repositories = config.location.repositories; repositories = config.location.repositories;
@ -233,10 +260,17 @@ let
keep_monthly = config.retention.keepMonthly; keep_monthly = config.retention.keepMonthly;
keep_yearly = config.retention.keepYearly; keep_yearly = config.retention.keepYearly;
checks = config.consistency.checks; checks = config.consistency.checks;
} // config.location.extraConfig // config.storage.extraConfig }
// config.retention.extraConfig // config.consistency.extraConfig // config.location.extraConfig
// config.output.extraConfig // config.hooks.extraConfig)); // config.storage.extraConfig
in { // config.retention.extraConfig
// config.consistency.extraConfig
// config.output.extraConfig
// config.hooks.extraConfig
)
);
in
{
meta.maintainers = [ lib.maintainers.DamienCassou ]; meta.maintainers = [ lib.maintainers.DamienCassou ];
options = { options = {
@ -272,25 +306,28 @@ in {
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
assertions = (lib.mapAttrsToList (backup: opts: { assertions =
assertion = opts.location.sourceDirectories == null (lib.mapAttrsToList (backup: opts: {
|| opts.location.patterns == null; assertion = opts.location.sourceDirectories == null || opts.location.patterns == null;
message = '' message = ''
Borgmatic backup configuration "${backup}" cannot specify both 'location.sourceDirectories' and 'location.patterns'. Borgmatic backup configuration "${backup}" cannot specify both 'location.sourceDirectories' and 'location.patterns'.
''; '';
}) cfg.backups) ++ (lib.mapAttrsToList (backup: opts: { }) cfg.backups)
assertion = !(opts.location.sourceDirectories == null ++ (lib.mapAttrsToList (backup: opts: {
&& opts.location.patterns == null); assertion = !(opts.location.sourceDirectories == null && opts.location.patterns == null);
message = '' message = ''
Borgmatic backup configuration "${backup}" must specify one of 'location.sourceDirectories' or 'location.patterns'. Borgmatic backup configuration "${backup}" must specify one of 'location.sourceDirectories' or 'location.patterns'.
''; '';
}) cfg.backups); }) cfg.backups);
xdg.configFile = with lib.attrsets; xdg.configFile =
mapAttrs' (configName: config: with lib.attrsets;
mapAttrs' (
configName: config:
nameValuePair ("borgmatic.d/" + configName + ".yaml") { nameValuePair ("borgmatic.d/" + configName + ".yaml") {
text = writeConfig config; text = writeConfig config;
}) cfg.backups; }
) cfg.backups;
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
}; };

View file

@ -1,11 +1,17 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.programs.bottom; cfg = config.programs.bottom;
tomlFormat = pkgs.formats.toml { }; tomlFormat = pkgs.formats.toml { };
in { in
{
options = { options = {
programs.bottom = { programs.bottom = {
enable = lib.mkEnableOption '' enable = lib.mkEnableOption ''

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) literalExpression mkOption types; inherit (lib) literalExpression mkOption types;
@ -37,7 +42,10 @@ let
}; };
mode = mkOption { mode = mkOption {
type = types.enum [ "file" "directory" ]; type = types.enum [
"file"
"directory"
];
default = "directory"; default = "directory";
description = '' description = ''
Does the current path redirect a file or a directory? Does the current path redirect a file or a directory?
@ -81,7 +89,8 @@ let
}; };
}; };
}; };
in { in
{
options.programs.boxxy = { options.programs.boxxy = {
enable = lib.mkEnableOption "boxxy: Boxes in badly behaving applications"; enable = lib.mkEnableOption "boxxy: Boxes in badly behaving applications";
@ -96,13 +105,11 @@ in {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
assertions = [ assertions = [
(lib.hm.assertions.assertPlatform "programs.boxxy" pkgs (lib.hm.assertions.assertPlatform "programs.boxxy" pkgs lib.platforms.linux)
lib.platforms.linux)
]; ];
home.file = lib.mkIf (cfg.rules != [ ]) { home.file = lib.mkIf (cfg.rules != [ ]) {
"${configPath}".source = "${configPath}".source = settingsFormat.generate "boxxy-config.yaml" { rules = cfg.rules; };
settingsFormat.generate "boxxy-config.yaml" { rules = cfg.rules; };
}; };
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ]; home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
@ -110,4 +117,3 @@ in {
meta.maintainers = with lib.hm.maintainers; [ nikp123 ]; meta.maintainers = with lib.hm.maintainers; [ nikp123 ];
} }

View file

@ -1,6 +1,17 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) literalExpression mkIf mkOption mkRenamedOptionModule types; inherit (lib)
literalExpression
mkIf
mkOption
mkRenamedOptionModule
types
;
cfg = config.programs.broot; cfg = config.programs.broot;
@ -13,7 +24,15 @@ let
modal = lib.mkEnableOption "modal (vim) mode"; modal = lib.mkEnableOption "modal (vim) mode";
verbs = mkOption { verbs = mkOption {
type = with types; listOf (attrsOf (oneOf [ bool str (listOf str) ])); type =
with types;
listOf (
attrsOf (oneOf [
bool
str
(listOf str)
])
);
default = [ ]; default = [ ];
example = literalExpression '' example = literalExpression ''
[ [
@ -116,53 +135,64 @@ let
}; };
}; };
shellInit = shell: shellInit =
shell:
# Using mkAfter to make it more likely to appear after other # Using mkAfter to make it more likely to appear after other
# manipulations of the prompt. # manipulations of the prompt.
lib.mkAfter '' lib.mkAfter ''
source ${ source ${
pkgs.runCommand "br.${shell}" { nativeBuildInputs = [ cfg.package ]; } pkgs.runCommand "br.${shell}" {
"broot --print-shell-function ${shell} > $out" nativeBuildInputs = [ cfg.package ];
} "broot --print-shell-function ${shell} > $out"
} }
''; '';
in { in
meta.maintainers = [ lib.hm.maintainers.aheaume lib.maintainers.dermetfan ]; {
meta.maintainers = [
lib.hm.maintainers.aheaume
lib.maintainers.dermetfan
];
imports = [ imports = [
(mkRenamedOptionModule [ "programs" "broot" "modal" ] [ (mkRenamedOptionModule
[ "programs" "broot" "modal" ]
[
"programs" "programs"
"broot" "broot"
"settings" "settings"
"modal" "modal"
]) ]
(mkRenamedOptionModule [ "programs" "broot" "verbs" ] [ )
(mkRenamedOptionModule
[ "programs" "broot" "verbs" ]
[
"programs" "programs"
"broot" "broot"
"settings" "settings"
"verbs" "verbs"
]) ]
(mkRenamedOptionModule [ "programs" "broot" "skin" ] [ )
(mkRenamedOptionModule
[ "programs" "broot" "skin" ]
[
"programs" "programs"
"broot" "broot"
"settings" "settings"
"skin" "skin"
]) ]
)
]; ];
options.programs.broot = { options.programs.broot = {
enable = lib.mkEnableOption "Broot, a better way to navigate directories"; enable = lib.mkEnableOption "Broot, a better way to navigate directories";
enableBashIntegration = enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { inherit config; };
lib.hm.shell.mkBashIntegrationOption { inherit config; };
enableFishIntegration = enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { inherit config; };
lib.hm.shell.mkFishIntegrationOption { inherit config; };
enableNushellIntegration = enableNushellIntegration = lib.hm.shell.mkNushellIntegrationOption { inherit config; };
lib.hm.shell.mkNushellIntegrationOption { inherit config; };
enableZshIntegration = enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; };
lib.hm.shell.mkZshIntegrationOption { inherit config; };
package = lib.mkPackageOption pkgs "broot" { }; package = lib.mkPackageOption pkgs "broot" { };
@ -190,9 +220,7 @@ in {
postBuild = '' postBuild = ''
rm $out/conf.hjson rm $out/conf.hjson
${lib.getExe pkgs.jq} --slurp add > $out/conf.hjson \ ${lib.getExe pkgs.jq} --slurp add > $out/conf.hjson \
<(${ <(${lib.getExe pkgs.hjson-go} -c ${cfg.package.src}/resources/default-conf/conf.hjson) \
lib.getExe pkgs.hjson-go
} -c ${cfg.package.src}/resources/default-conf/conf.hjson) \
${jsonFormat.generate "broot-config.json" cfg.settings} ${jsonFormat.generate "broot-config.json" cfg.settings}
''; '';
}; };
@ -205,8 +233,7 @@ in {
fish.shellInit = mkIf cfg.enableFishIntegration (shellInit "fish"); fish.shellInit = mkIf cfg.enableFishIntegration (shellInit "fish");
nushell.extraConfig = nushell.extraConfig = mkIf cfg.enableNushellIntegration (shellInit "nushell");
mkIf cfg.enableNushellIntegration (shellInit "nushell");
}; };
}; };
} }

View file

@ -1,8 +1,21 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.programs.browserpass; cfg = config.programs.browserpass;
browsers = [ "brave" "chrome" "chromium" "firefox" "librewolf" "vivaldi" ]; browsers = [
in { "brave"
"chrome"
"chromium"
"firefox"
"librewolf"
"vivaldi"
];
in
{
options = { options = {
programs.browserpass = { programs.browserpass = {
enable = lib.mkEnableOption "the browserpass extension host application"; enable = lib.mkEnableOption "the browserpass extension host application";
@ -17,39 +30,51 @@ in {
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home.file = lib.foldl' (a: b: a // b) { } (lib.concatMap (x: home.file = lib.foldl' (a: b: a // b) { } (
lib.concatMap (
x:
with pkgs.stdenv; with pkgs.stdenv;
if x == "brave" then if x == "brave" then
let let
dir = if isDarwin then dir =
if isDarwin then
"Library/Application Support/BraveSoftware/Brave-Browser/NativeMessagingHosts" "Library/Application Support/BraveSoftware/Brave-Browser/NativeMessagingHosts"
else else
".config/BraveSoftware/Brave-Browser/NativeMessagingHosts"; ".config/BraveSoftware/Brave-Browser/NativeMessagingHosts";
in [{ in
[
{
# Policies are read from `/etc/brave/policies` only # Policies are read from `/etc/brave/policies` only
# https://github.com/brave/brave-browser/issues/19052 # https://github.com/brave/brave-browser/issues/19052
"${dir}/com.github.browserpass.native.json".source = "${dir}/com.github.browserpass.native.json".source =
"${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json"; "${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json";
}] }
]
else if x == "chrome" then else if x == "chrome" then
let let
dir = if isDarwin then dir =
if isDarwin then
"Library/Application Support/Google/Chrome/NativeMessagingHosts" "Library/Application Support/Google/Chrome/NativeMessagingHosts"
else else
".config/google-chrome/NativeMessagingHosts"; ".config/google-chrome/NativeMessagingHosts";
in [{ in
[
{
"${dir}/com.github.browserpass.native.json".source = "${dir}/com.github.browserpass.native.json".source =
"${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json"; "${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json";
"${dir}/../policies/managed/com.github.browserpass.native.json".source = "${dir}/../policies/managed/com.github.browserpass.native.json".source =
"${pkgs.browserpass}/lib/browserpass/policies/chromium/com.github.browserpass.native.json"; "${pkgs.browserpass}/lib/browserpass/policies/chromium/com.github.browserpass.native.json";
}] }
]
else if x == "chromium" then else if x == "chromium" then
let let
dir = if isDarwin then dir =
if isDarwin then
"Library/Application Support/Chromium/NativeMessagingHosts" "Library/Application Support/Chromium/NativeMessagingHosts"
else else
".config/chromium/NativeMessagingHosts"; ".config/chromium/NativeMessagingHosts";
in [ in
[
{ {
"${dir}/com.github.browserpass.native.json".source = "${dir}/com.github.browserpass.native.json".source =
"${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json"; "${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json";
@ -61,38 +86,52 @@ in {
] ]
else if x == "firefox" then else if x == "firefox" then
let let
dir = if isDarwin then dir =
if isDarwin then
"Library/Application Support/Mozilla/NativeMessagingHosts" "Library/Application Support/Mozilla/NativeMessagingHosts"
else else
".mozilla/native-messaging-hosts"; ".mozilla/native-messaging-hosts";
in [{ in
[
{
"${dir}/com.github.browserpass.native.json".source = "${dir}/com.github.browserpass.native.json".source =
"${pkgs.browserpass}/lib/browserpass/hosts/firefox/com.github.browserpass.native.json"; "${pkgs.browserpass}/lib/browserpass/hosts/firefox/com.github.browserpass.native.json";
}] }
]
else if x == "librewolf" then else if x == "librewolf" then
let let
dir = if isDarwin then dir =
if isDarwin then
"Library/Application Support/LibreWolf/NativeMessagingHosts" "Library/Application Support/LibreWolf/NativeMessagingHosts"
else else
".librewolf/native-messaging-hosts"; ".librewolf/native-messaging-hosts";
in [{ in
[
{
"${dir}/com.github.browserpass.native.json".source = "${dir}/com.github.browserpass.native.json".source =
"${pkgs.browserpass}/lib/browserpass/hosts/firefox/com.github.browserpass.native.json"; "${pkgs.browserpass}/lib/browserpass/hosts/firefox/com.github.browserpass.native.json";
}] }
]
else if x == "vivaldi" then else if x == "vivaldi" then
let let
dir = if isDarwin then dir =
if isDarwin then
"Library/Application Support/Vivaldi/NativeMessagingHosts" "Library/Application Support/Vivaldi/NativeMessagingHosts"
else else
".config/vivaldi/NativeMessagingHosts"; ".config/vivaldi/NativeMessagingHosts";
in [{ in
[
{
"${dir}/com.github.browserpass.native.json".source = "${dir}/com.github.browserpass.native.json".source =
"${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json"; "${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json";
"${dir}/../policies/managed/com.github.browserpass.native.json".source = "${dir}/../policies/managed/com.github.browserpass.native.json".source =
"${pkgs.browserpass}/lib/browserpass/policies/chromium/com.github.browserpass.native.json"; "${pkgs.browserpass}/lib/browserpass/policies/chromium/com.github.browserpass.native.json";
}] }
]
else else
throw "unknown browser ${x}") cfg.browsers); throw "unknown browser ${x}"
) cfg.browsers
);
}; };
} }

Some files were not shown because too many files have changed in this diff Show more