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

View file

@ -1,9 +1,12 @@
{ pkgs
{
pkgs,
# 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
@ -19,86 +22,124 @@ let
# Caveat: even if the package is reached by a different means, the
# path above will be shown and not e.g.
# `${config.services.foo.package}`.
scrubDerivations = prefixPath: attrs:
scrubDerivations =
prefixPath: attrs:
let
scrubDerivation = name: value:
let pkgAttrName = prefixPath + "." + name;
in if lib.isAttrs value then
scrubDerivation =
name: value:
let
pkgAttrName = prefixPath + "." + name;
in
if lib.isAttrs value then
scrubDerivations pkgAttrName value
// lib.optionalAttrs (lib.isDerivation value) {
outPath = "\${${pkgAttrName}}";
}
else
value;
in lib.mapAttrs scrubDerivation attrs;
in
lib.mapAttrs scrubDerivation attrs;
# Make sure the used package is scrubbed to avoid actually
# instantiating derivations.
scrubbedPkgsModule = {
imports = [{
imports = [
{
_module.args = {
pkgs = lib.mkForce (scrubDerivations "pkgs" pkgs);
pkgs_i686 = lib.mkForce { };
};
}];
}
];
};
dontCheckDefinitions = { _module.check = false; };
dontCheckDefinitions = {
_module.check = false;
};
gitHubDeclaration = user: repo: subpath:
let urlRef = if isReleaseBranch then "release-${release}" else "master";
in {
gitHubDeclaration =
user: repo: subpath:
let
urlRef = if isReleaseBranch then "release-${release}" else "master";
in
{
url = "https://github.com/${user}/${repo}/blob/${urlRef}/${subpath}";
name = "<${repo}/${subpath}>";
};
hmPath = toString ./..;
buildOptionsDocs = args@{ modules, includeModuleSystemOptions ? true, ... }:
buildOptionsDocs =
args@{
modules,
includeModuleSystemOptions ? true,
...
}:
let
options = (lib.evalModules {
options =
(lib.evalModules {
inherit modules;
class = "homeManager";
}).options;
in pkgs.buildPackages.nixosOptionsDoc ({
options = if includeModuleSystemOptions then
options
else
builtins.removeAttrs options [ "_module" ];
transformOptions = opt:
opt // {
in
pkgs.buildPackages.nixosOptionsDoc (
{
options =
if includeModuleSystemOptions then options else builtins.removeAttrs options [ "_module" ];
transformOptions =
opt:
opt
// {
# Clean up declaration sites to not refer to the Home Manager
# source tree.
declarations = map (decl:
declarations = map (
decl:
if lib.hasPrefix hmPath (toString decl) then
gitHubDeclaration "nix-community" "home-manager"
(lib.removePrefix "/" (lib.removePrefix hmPath (toString decl)))
gitHubDeclaration "nix-community" "home-manager" (
lib.removePrefix "/" (lib.removePrefix hmPath (toString decl))
)
else if decl == "lib/modules.nix" then
# TODO: handle this in a better way (may require upstream
# changes to nixpkgs)
gitHubDeclaration "NixOS" "nixpkgs" decl
else
decl) opt.declarations;
decl
) opt.declarations;
};
} // builtins.removeAttrs args [ "modules" "includeModuleSystemOptions" ]);
}
// builtins.removeAttrs args [
"modules"
"includeModuleSystemOptions"
]
);
hmOptionsDocs = buildOptionsDocs {
modules = import ../modules/modules.nix {
modules =
import ../modules/modules.nix {
inherit lib pkgs;
check = false;
} ++ [ scrubbedPkgsModule ];
}
++ [ scrubbedPkgsModule ];
variablelistId = "home-manager-options";
};
nixosOptionsDocs = buildOptionsDocs {
modules = [ ../nixos scrubbedPkgsModule dontCheckDefinitions ];
modules = [
../nixos
scrubbedPkgsModule
dontCheckDefinitions
];
includeModuleSystemOptions = false;
variablelistId = "nixos-options";
optionIdPrefix = "nixos-opt-";
};
nixDarwinOptionsDocs = buildOptionsDocs {
modules = [ ../nix-darwin scrubbedPkgsModule dontCheckDefinitions ];
modules = [
../nix-darwin
scrubbedPkgsModule
dontCheckDefinitions
];
includeModuleSystemOptions = false;
variablelistId = "nix-darwin-options";
optionIdPrefix = "nix-darwin-opt-";
@ -108,11 +149,15 @@ let
revision = "release-${release-config.release}";
# Generate the `man home-configuration.nix` package
home-configuration-manual =
pkgs.runCommand "home-configuration-reference-manpage" {
nativeBuildInputs =
[ pkgs.buildPackages.installShellFiles pkgs.nixos-render-docs ];
pkgs.runCommand "home-configuration-reference-manpage"
{
nativeBuildInputs = [
pkgs.buildPackages.installShellFiles
pkgs.nixos-render-docs
];
allowedReferences = [ "out" ];
} ''
}
''
# Generate manpages.
mkdir -p $out/share/man/man5
mkdir -p $out/share/man/man1
@ -135,13 +180,17 @@ let
};
html = home-manager-manual;
htmlOpenTool = pkgs.callPackage ./html-open-tool.nix { } { inherit html; };
in {
in
{
options = {
# TODO: Use `hmOptionsDocs.optionsJSON` directly once upstream
# `nixosOptionsDoc` is more customizable.
json = pkgs.runCommand "options.json" {
json =
pkgs.runCommand "options.json"
{
meta.description = "List of Home Manager options in JSON format";
} ''
}
''
mkdir -p $out/{share/doc,nix-support}
cp -a ${hmOptionsDocs.optionsJSON}/share/doc/nixos $out/share/doc/home-manager
substitute \
@ -158,13 +207,18 @@ in {
manual = { inherit html htmlOpenTool; };
# Unstable, mainly for CI.
jsonModuleMaintainers = pkgs.writeText "hm-module-maintainers.json" (let
jsonModuleMaintainers = pkgs.writeText "hm-module-maintainers.json" (
let
result = lib.evalModules {
modules = import ../modules/modules.nix {
modules =
import ../modules/modules.nix {
inherit lib pkgs;
check = false;
} ++ [ scrubbedPkgsModule ];
}
++ [ scrubbedPkgsModule ];
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
supportedSystems = [
"aarch64-darwin"
@ -28,7 +33,12 @@
p-build = pkgs.writeShellScriptBin "p-build" ''
set -euo pipefail
export PATH=${lib.makeBinPath [ pkgs.coreutils pkgs.rsass ]}
export PATH=${
lib.makeBinPath [
pkgs.coreutils
pkgs.rsass
]
}
tmpfile=$(mktemp -d)
trap "rm -r $tmpfile" EXIT
@ -42,20 +52,25 @@
};
releaseInfo = lib.importJSON ../release.json;
in {
devShells = forAllSystems (system:
in
{
devShells = forAllSystems (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
fpkgs = flakePkgs pkgs;
in {
in
{
default = pkgs.mkShell {
name = "hm-docs";
packages = [ fpkgs.p-build ];
};
});
}
);
# Expose the docs outputs
packages = forAllSystems (system:
packages = forAllSystems (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
docs = import ./default.nix {
@ -63,10 +78,12 @@
release = releaseInfo.release;
isReleaseBranch = releaseInfo.isReleaseBranch;
};
in {
in
{
inherit (docs) manPages jsonModuleMaintainers;
inherit (docs.manual) html htmlOpenTool;
inherit (docs.options) json;
});
}
);
};
}

View file

@ -1,7 +1,15 @@
{ stdenv, lib, documentation-highlighter, revision, home-manager-options
, nixos-render-docs }:
let outputPath = "share/doc/home-manager";
in stdenv.mkDerivation {
{
stdenv,
lib,
documentation-highlighter,
revision,
home-manager-options,
nixos-render-docs,
}:
let
outputPath = "share/doc/home-manager";
in
stdenv.mkDerivation {
name = "home-manager-manual";
nativeBuildInputs = [ nixos-render-docs ];
@ -61,5 +69,7 @@ in stdenv.mkDerivation {
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
, name ? "${pathName}-help" }:
{
writeShellScriptBin,
makeDesktopItem,
symlinkJoin,
}:
{
html,
pathName ? "home-manager",
projectName ? pathName,
name ? "${pathName}-help",
}:
let
helpScript = writeShellScriptBin name ''
set -euo pipefail
@ -30,7 +38,11 @@ let
exec = "${helpScript}/bin/${name}";
categories = [ "System" ];
};
in symlinkJoin {
in
symlinkJoin {
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;
in {
{
lib,
flake-parts-lib,
moduleLocation,
...
}:
let
inherit (lib)
toString
mapAttrs
mkOption
types
;
in
{
options = {
flake = flake-parts-lib.mkSubmoduleOptions {
homeConfigurations = mkOption {
@ -17,11 +29,13 @@ in {
homeModules = mkOption {
type = types.lazyAttrsOf types.deferredModule;
default = { };
apply = mapAttrs (k: v: {
apply = mapAttrs (
k: v: {
_class = "homeManager";
_file = "${toString moduleLocation}#homeModules.${k}";
imports = [ v ];
});
}
);
description = ''
Home Manager modules.

View file

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

View file

@ -2,46 +2,70 @@
# file is considered internal and the exported fields may change without
# warning.
{ newsJsonFile, newsReadIdsFile ? null }:
{
newsJsonFile,
newsReadIdsFile ? null,
}:
let
inherit (builtins)
concatStringsSep filter hasAttr isString length readFile replaceStrings sort
split;
concatStringsSep
filter
hasAttr
isString
length
readFile
replaceStrings
sort
split
;
newsJson = builtins.fromJSON (builtins.readFile newsJsonFile);
# Sorted and relevant entries.
relevantEntries =
sort (a: b: a.time > b.time) (filter (e: e.condition) newsJson.entries);
relevantEntries = sort (a: b: a.time > b.time) (filter (e: e.condition) newsJson.entries);
newsReadIds = if newsReadIdsFile == null then
newsReadIds =
if newsReadIdsFile == null then
{ }
else
let ids = filter isString (split "\n" (readFile newsReadIdsFile));
in builtins.listToAttrs (map (id: {
let
ids = filter isString (split "\n" (readFile newsReadIdsFile));
in
builtins.listToAttrs (
map (id: {
name = id;
value = null;
}) ids);
}) ids
);
newsIsRead = entry: hasAttr entry.id newsReadIds;
newsUnread = let pred = entry: entry.condition && !newsIsRead entry;
in filter pred relevantEntries;
newsUnread =
let
pred = entry: entry.condition && !newsIsRead entry;
in
filter pred relevantEntries;
prettyTime = t: replaceStrings [ "T" "+00:00" ] [ " " "" ] t;
layoutNews = entries:
layoutNews =
entries:
let
mkTextEntry = entry:
let flag = if newsIsRead entry then "read" else "unread";
in ''
mkTextEntry =
entry:
let
flag = if newsIsRead entry then "read" else "unread";
in
''
* ${prettyTime entry.time} [${flag}]
${replaceStrings [ "\n" ] [ "\n " ] entry.message}
'';
in concatStringsSep "\n\n" (map mkTextEntry entries);
in {
in
concatStringsSep "\n\n" (map mkTextEntry entries);
in
{
meta = {
numUnread = length newsUnread;
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
, pkgs
pkgs,
# Path to use as the Home Manager channel.
, path ? null }:
path ? null,
}:
let
pathStr = if path == null then "" else path;
nixos-option = pkgs.nixos-option or (callPackage
(pkgs.path + "/nixos/modules/installer/tools/nixos-option") { });
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;
nativeBuildInputs = [ gettext ];
meta = {
@ -23,7 +37,8 @@ in runCommand "home-manager" {
platforms = lib.platforms.unix;
license = lib.licenses.mit;
};
} ''
}
''
install -v -D -m755 ${./home-manager} $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
inherit (pkgs.lib)
concatMapStringsSep fileContents filter length optionalString removeSuffix
replaceStrings splitString;
concatMapStringsSep
fileContents
filter
length
optionalString
removeSuffix
replaceStrings
splitString
;
env = import ../modules {
configuration = if confAttr == "" || confAttr == null then
confPath
else
(import confPath).${confAttr};
configuration =
if confAttr == "" || confAttr == null then confPath else (import confPath).${confAttr};
pkgs = pkgs;
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
'';
in runCommand "home-manager-install" {
in
runCommand "home-manager-install"
{
propagatedBuildInputs = [ home-manager ];
preferLocalBuild = true;
shellHookOnly = true;
shellHook = "exec ${home-manager}/bin/home-manager init --switch --no-flake";
} ''
}
''
${hmBashLibInit}
_iError 'This derivation is not buildable, please run it using nix-shell.'
exit 1

View file

@ -1,10 +1,21 @@
{ lib }: {
{ lib }:
{
hm = (import ../modules/lib/stdlib-extended.nix lib).hm;
homeManagerConfiguration = { modules ? [ ], pkgs, lib ? pkgs.lib
, extraSpecialArgs ? { }, check ? true
homeManagerConfiguration =
{
modules ? [ ],
pkgs,
lib ? pkgs.lib,
extraSpecialArgs ? { },
check ? true,
# Deprecated:
, configuration ? null, extraModules ? null, stateVersion ? null
, username ? null, homeDirectory ? null, system ? null }@args:
configuration ? null,
extraModules ? null,
stateVersion ? null,
username ? null,
homeDirectory ? null,
system ? null,
}@args:
let
msgForRemovedArg = ''
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
'';
throwForRemovedArgs = v:
throwForRemovedArgs =
v:
let
used = builtins.filter (n: (args.${n} or null) != null) [
"configuration"
@ -30,20 +42,34 @@
"extraModules"
"system"
];
msg = msgForRemovedArg + ''
msg =
msgForRemovedArg
+ ''
Deprecated args passed: '' + builtins.concatStringsSep " " used;
in lib.throwIf (used != [ ]) msg v;
Deprecated args passed: ''
+ builtins.concatStringsSep " " used;
in
lib.throwIf (used != [ ]) msg v;
in throwForRemovedArgs (import ../modules {
inherit pkgs lib check extraSpecialArgs;
configuration = { ... }: {
in
throwForRemovedArgs (
import ../modules {
inherit
pkgs
lib
check
extraSpecialArgs
;
configuration =
{ ... }:
{
imports = modules ++ [ { programs.home-manager.path = "${../.}"; } ];
nixpkgs = {
config = lib.mkDefault pkgs.config;
inherit (pkgs) overlays;
};
};
});
}
);
}

View file

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

View file

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

View file

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

View file

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

View file

@ -15,7 +15,12 @@
# below for changes:
# https://github.com/NixOS/nixpkgs/blob/nixpkgs-unstable/pkgs/development/libraries/glibc/nix-locale-archive.patch
{ lib, pkgs, config, ... }:
{
lib,
pkgs,
config,
...
}:
let
inherit (config.i18n) glibcLocales;
@ -25,14 +30,20 @@ let
archivePath = "${glibcLocales}/lib/locale/locale-archive";
# 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;
} else if lib.versionAtLeast version "2.11" then {
}
else if lib.versionAtLeast version "2.11" then
{
LOCALE_ARCHIVE_2_11 = archivePath;
} else
}
else
{ };
in {
in
{
meta.maintainers = with lib.maintainers; [ midchildan ];
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.
, check ? true
check ? true,
# Extra arguments passed to specialArgs.
, extraSpecialArgs ? { } }:
extraSpecialArgs ? { },
}:
let
collectFailed = cfg:
map (x: x.message) (lib.filter (x: !x.assertion) cfg.assertions);
collectFailed = cfg: map (x: x.message) (lib.filter (x: !x.assertion) cfg.assertions);
showWarnings = res:
let f = w: x: builtins.trace "warning: ${w}" x;
in lib.fold f res res.config.warnings;
showWarnings =
res:
let
f = w: x: builtins.trace "warning: ${w}" x;
in
lib.fold f res res.config.warnings;
extendedLib = import ./lib/stdlib-extended.nix lib;
@ -24,24 +30,33 @@ let
rawModule = extendedLib.evalModules {
modules = [ configuration ] ++ hmModules;
class = "homeManager";
specialArgs = { modulesPath = builtins.toString ./.; } // extraSpecialArgs;
specialArgs = {
modulesPath = builtins.toString ./.;
} // extraSpecialArgs;
};
moduleChecks = raw:
showWarnings (let
moduleChecks =
raw:
showWarnings (
let
failed = collectFailed raw.config;
failedStr = lib.concatStringsSep "\n" (map (x: "- ${x}") failed);
in if failed == [ ] then
in
if failed == [ ] then
raw
else
throw ''
Failed assertions:
${failedStr}'');
${failedStr}''
);
withExtraAttrs = rawModule:
let module = moduleChecks rawModule;
in {
withExtraAttrs =
rawModule:
let
module = moduleChecks rawModule;
in
{
inherit (module) options config;
activationPackage = module.config.home.activationPackage;
@ -50,11 +65,13 @@ let
activation-script = module.config.home.activationPackage;
newsDisplay = rawModule.config.news.display;
newsEntries = lib.sort (a: b: a.time > b.time)
(lib.filter (a: a.condition) rawModule.config.news.entries);
newsEntries = lib.sort (a: b: a.time > b.time) (
lib.filter (a: a.condition) rawModule.config.news.entries
);
inherit (module._module.args) pkgs;
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
@ -6,18 +11,24 @@ let
homeDirectory = config.home.homeDirectory;
fileType = (import lib/file-type.nix {
fileType =
(import lib/file-type.nix {
inherit homeDirectory lib pkgs;
}).fileType;
sourceStorePath = file:
sourceStorePath =
file:
let
sourcePath = toString file.source;
sourceName = config.lib.strings.storeFileName (baseNameOf sourcePath);
in
if builtins.hasContext sourcePath
then file.source
else builtins.path { path = file.source; name = sourceName; };
if builtins.hasContext sourcePath then
file.source
else
builtins.path {
path = file.source;
name = sourceName;
};
in
@ -37,15 +48,17 @@ in
};
config = {
assertions = [(
assertions = [
(
let
dups =
lib.attrNames
(lib.filterAttrs (n: v: v > 1)
(lib.foldAttrs (acc: v: acc + v) 0
(lib.mapAttrsToList (n: v: { ${v.target} = 1; }) cfg)));
dups = lib.attrNames (
lib.filterAttrs (n: v: v > 1) (
lib.foldAttrs (acc: v: acc + v) 0 (lib.mapAttrsToList (n: v: { ${v.target} = 1; }) cfg)
)
);
dupsStr = lib.concatStringsSep ", " dups;
in {
in
{
assertion = dups == [ ];
message = ''
Conflicting managed target files: ${dupsStr}
@ -56,7 +69,8 @@ in
conflict1 = { source = ./foo.nix; target = "baz"; };
conflict2 = { source = ./bar.nix; target = "baz"; };
}'';
})
}
)
];
# 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
# absolute path of the `bar` file relative the configuration file.
lib.file.mkOutOfStoreSymlink = path:
lib.file.mkOutOfStoreSymlink =
path:
let
pathStr = toString path;
name = lib.hm.strings.storeFileName (baseNameOf pathStr);
@ -80,10 +95,9 @@ in
let
# Paths that should be forcibly overwritten by Home Manager.
# Caveat emptor!
forcedPaths =
lib.concatMapStringsSep " " (p: ''"$HOME"/${lib.escapeShellArg p}'')
(lib.mapAttrsToList (n: v: v.target)
(lib.filterAttrs (n: v: v.force) cfg));
forcedPaths = lib.concatMapStringsSep " " (p: ''"$HOME"/${lib.escapeShellArg p}'') (
lib.mapAttrsToList (n: v: v.target) (lib.filterAttrs (n: v: v.force) cfg)
);
storeDir = lib.escapeShellArg builtins.storeDir;
@ -225,7 +239,8 @@ in
home.activation.checkFilesChanged = lib.hm.dag.entryBefore [ "linkGeneration" ] (
let
homeDirArg = lib.escapeShellArg homeDirectory;
in ''
in
''
function _cmp() {
if [[ -d $1 && -d $2 ]]; then
diff -rq "$1" "$2" &> /dev/null
@ -234,15 +249,19 @@ in
fi
}
declare -A changedFiles
'' + lib.concatMapStrings (v:
''
+ lib.concatMapStrings (
v:
let
sourceArg = lib.escapeShellArg (sourceStorePath v);
targetArg = lib.escapeShellArg v.target;
in ''
in
''
_cmp ${sourceArg} ${homeDirArg}/${targetArg} \
&& changedFiles[${targetArg}]=0 \
|| changedFiles[${targetArg}]=1
'') (lib.filter (v: v.onChange != "") (lib.attrValues cfg))
''
) (lib.filter (v: v.onChange != "") (lib.attrValues cfg))
+ ''
unset -f _cmp
''
@ -263,12 +282,13 @@ in
# Symlink directories and files that have the right execute bit.
# Copy files that need their execute bit changed.
home-files = pkgs.runCommandLocal
"home-manager-files"
home-files =
pkgs.runCommandLocal "home-manager-files"
{
nativeBuildInputs = [ pkgs.xorg.lndir ];
}
(''
(
''
mkdir -p $out
# Needed in case /nix is a symbolic link.
@ -330,18 +350,19 @@ in
fi
fi
}
'' + lib.concatStrings (
''
+ lib.concatStrings (
lib.mapAttrsToList (n: v: ''
insertFile ${
lib.escapeShellArgs [
(sourceStorePath v)
v.target
(if v.executable == null
then "inherit"
else toString v.executable)
(if v.executable == null then "inherit" else toString v.executable)
(toString v.recursive)
]}
]
}
'') cfg
));
)
);
};
}

View file

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

View file

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

View file

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

View file

@ -1,10 +1,22 @@
{ config, pkgs, lib, ... }:
{
config,
pkgs,
lib,
...
}:
let
inherit (lib) literalExpression mkIf mkOption mkRemovedOptionModule types;
inherit (lib)
literalExpression
mkIf
mkOption
mkRemovedOptionModule
types
;
cfg = config.i18n.inputMethod.kime;
in {
in
{
imports = [
(mkRemovedOptionModule [ "i18n" "inputMethod" "kime" "config" ] ''
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") {

View file

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

View file

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

View file

@ -29,7 +29,8 @@ let
inherit (lib) types mkOption; # added by Home Manager
launchdTypes = import ./types.nix { inherit config lib; };
in {
in
{
freeformType = with types; attrsOf anything; # added by Home Manager
options = {
@ -82,11 +83,14 @@ in {
inetdCompatibility = mkOption {
default = null;
example = { Wait = true; };
example = {
Wait = true;
};
description = ''
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 = {
Wait = mkOption {
type = types.nullOr (types.either types.bool types.str);
@ -98,7 +102,8 @@ in {
'';
};
};
});
}
);
};
LimitLoadToHosts = mkOption {
@ -120,7 +125,12 @@ in {
};
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;
description = ''
This configuration file only applies to sessions of the type specified. This key is used in concert
@ -177,7 +187,9 @@ in {
};
KeepAlive = mkOption {
type = types.nullOr (types.either types.bool (types.submodule {
type = types.nullOr (
types.either types.bool (
types.submodule {
options = {
SuccessfulExit = mkOption {
@ -238,7 +250,9 @@ in {
};
};
}));
}
)
);
default = null;
description = ''
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 {
default = null;
example = [{
example = [
{
Hour = 2;
Minute = 30;
}];
}
];
description = ''
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
@ -442,7 +458,8 @@ in {
Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following
keys apply:
'';
type = types.nullOr (types.submodule {
type = types.nullOr (
types.submodule {
options = {
Core = mkOption {
type = types.nullOr types.int;
@ -524,17 +541,21 @@ in {
'';
};
};
});
}
);
};
HardResourceLimits = mkOption {
default = null;
example = { NumberOfFiles = 4096; };
example = {
NumberOfFiles = 4096;
};
description = ''
Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following
keys apply:
'';
type = types.nullOr (types.submodule {
type = types.nullOr (
types.submodule {
options = {
Core = mkOption {
type = types.nullOr types.int;
@ -616,7 +637,8 @@ in {
'';
};
};
});
}
);
};
Nice = mkOption {
@ -628,8 +650,14 @@ in {
};
ProcessType = mkOption {
type = types.nullOr
(types.enum [ "Background" "Standard" "Adaptive" "Interactive" ]);
type = types.nullOr (
types.enum [
"Background"
"Standard"
"Adaptive"
"Interactive"
]
);
default = null;
example = "Background";
description = ''
@ -694,7 +722,11 @@ in {
MachServices = mkOption {
default = null;
example = { "org.nixos.service" = { ResetAtClose = true; }; };
example = {
"org.nixos.service" = {
ResetAtClose = true;
};
};
description = ''
This optional key is used to specify Mach services to be registered with the Mach bootstrap sub-system.
Each key in this dictionary should be the name of service to be advertised. The value of the key must
@ -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
launchd.
'';
type = types.nullOr (types.attrsOf (types.either types.bool
(types.submodule {
type = types.nullOr (
types.attrsOf (
types.either types.bool (
types.submodule {
options = {
ResetAtClose = mkOption {
type = types.nullOr types.bool;
@ -728,7 +762,10 @@ in {
'';
};
};
})));
}
)
)
);
};
LaunchEvents = mkOption {
@ -790,10 +827,18 @@ in {
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 = {
SockType = mkOption {
type = types.nullOr (types.enum [ "stream" "dgram" "seqpacket" ]);
type = types.nullOr (
types.enum [
"stream"
"dgram"
"seqpacket"
]
);
default = null;
description = ''
This optional key tells launchctl what type of socket to create. The default is "stream" and
@ -827,7 +872,12 @@ in {
};
SockFamily = mkOption {
type = types.nullOr (types.enum [ "IPv4" "IPv6" ]);
type = types.nullOr (
types.enum [
"IPv4"
"IPv6"
]
);
default = null;
description = ''
This optional key can be used to specifically request that "IPv4" or "IPv6" socket(s) be created.
@ -872,8 +922,7 @@ in {
};
Bonjour = mkOption {
type =
types.nullOr (types.either types.bool (types.listOf types.str));
type = types.nullOr (types.either types.bool (types.listOf types.str));
default = null;
description = ''
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, ... }:
let
inherit (lib) imap1 types mkOption showOption mergeDefinitions;
inherit (builtins) map filter length deepSeq throw toString concatLists;
inherit (lib)
imap1
types
mkOption
showOption
mergeDefinitions
;
inherit (builtins)
map
filter
length
deepSeq
throw
toString
concatLists
;
inherit (lib.options) showDefs;
wildcardText = lib.literalMD "`*`";
/* *
/*
*
A type of list which does not allow duplicate elements. The base/inner
list type to use (e.g. `types.listOf` or `types.nonEmptyListOf`) is passed
via argument `listType`, which must be the final type and not a function.
@ -25,49 +40,63 @@ let
The implementation of this function is similar to that of
`types.nonEmptyListOf`.
*/
types'.uniqueList = listType:
listType // {
description = "unique ${
types.optionDescriptionPhrase (class: class == "noun") listType
}";
types'.uniqueList =
listType:
listType
// {
description = "unique ${types.optionDescriptionPhrase (class: class == "noun") listType}";
substSubModules = m: types'.uniqueList (listType.substSubModules m);
# This has been taken from the implementation of `types.listOf`, but has
# been modified to throw on duplicates. This check cannot be done in the
# `check` fn as this check is deep/strict, and because `check` runs
# prior to merging.
merge = loc: defs:
merge =
loc: defs:
let
# Each element of `dupes` is a list. When there are duplicates,
# later lists will be duplicates of earlier lists, so just throw on
# the first set of duplicates found so that we don't have duplicate
# error msgs.
checked = filter (li:
checked = filter (
li:
if length li > 1 then
throw ''
The option `${
showOption loc
}' contains duplicate entries after merging:
The option `${showOption loc}' contains duplicate entries after merging:
${showDefs li}''
else
false) dupes;
dupes =
map (def: filter (def': def'.value == def.value) merged) merged;
merged = filter (x: x ? value) (concatLists (imap1 (n: def:
imap1 (m: el:
false
) dupes;
dupes = map (def: filter (def': def'.value == def.value) merged) merged;
merged = filter (x: x ? value) (
concatLists (
imap1 (
n: def:
imap1 (
m: el:
let
inherit (def) file;
loc' = loc
++ [ "[definition ${toString n}-entry ${toString m}]" ];
in (mergeDefinitions loc' listType.nestedTypes.elemType [{
loc' = loc ++ [ "[definition ${toString n}-entry ${toString m}]" ];
in
(mergeDefinitions loc' listType.nestedTypes.elemType [
{
inherit file;
value = el;
}]).optionalValue // {
}
]).optionalValue
// {
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 {
StartCalendarInterval = let
in
{
StartCalendarInterval =
let
CalendarIntervalEntry = types.submodule {
options = {
Minute = mkOption {
@ -116,6 +145,6 @@ in {
};
};
};
in types.either CalendarIntervalEntry
(types'.uniqueList (types.nonEmptyListOf CalendarIntervalEntry));
in
types.either CalendarIntervalEntry (types'.uniqueList (types.nonEmptyListOf CalendarIntervalEntry));
}

View file

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

View file

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

View file

@ -9,13 +9,23 @@
{ lib }:
let inherit (lib) all filterAttrs head hm mapAttrs length tail toposort;
in {
let
inherit (lib)
all
filterAttrs
head
hm
mapAttrs
length
tail
toposort
;
in
{
empty = { };
isEntry = e: e ? data && e ? after && e ? before;
isDag = dag:
builtins.isAttrs dag && all hm.dag.isEntry (builtins.attrValues dag);
isDag = dag: builtins.isAttrs dag && all hm.dag.isEntry (builtins.attrValues dag);
# Takes an attribute set containing entries built by entryAnywhere,
# entryAfter, and entryBefore to a topologically sorted list of
@ -73,11 +83,10 @@ in {
# ];
# }
# true
topoSort = dag:
topoSort =
dag:
let
dagBefore = dag: name:
builtins.attrNames
(filterAttrs (n: v: builtins.elem name v.before) dag);
dagBefore = dag: name: builtins.attrNames (filterAttrs (n: v: builtins.elem name v.before) dag);
normalizedDag = mapAttrs (n: v: {
name = n;
data = v.data;
@ -85,9 +94,12 @@ in {
}) dag;
before = a: b: builtins.elem a.name b.after;
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;
} else
}
else
sorted;
# 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
# generated nodes are then placed before or after those dependencies.
entriesBetween = tag:
entriesBetween =
tag:
let
go = i: before: after: entries:
go =
i: before: after: entries:
let
name = "${tag}-${toString i}";
i' = i + 1;
in if entries == [ ] then
in
if entries == [ ] then
hm.dag.empty
else if length entries == 1 then {
else if length entries == 1 then
{
"${name}" = hm.dag.entryBetween before after (head entries);
} else
}
else
{
"${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 [ ] [ ];
entriesAfter = tag: hm.dag.entriesBetween tag [ ];

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,13 +2,32 @@
let
inherit (lib)
concatStringsSep defaultFunctor fixedWidthNumber hm imap1 isAttrs isList
length listToAttrs mapAttrs mkIf mkOrder mkOption mkOptionType nameValuePair
stringLength types warn;
concatStringsSep
defaultFunctor
fixedWidthNumber
hm
imap1
isAttrs
isList
length
listToAttrs
mapAttrs
mkIf
mkOrder
mkOption
mkOptionType
nameValuePair
stringLength
types
warn
;
dagEntryOf = elemType:
dagEntryOf =
elemType:
let
submoduleType = types.submodule ({ name, ... }: {
submoduleType = types.submodule (
{ name, ... }:
{
options = {
data = mkOption { type = elemType; };
after = mkOption { type = with types; listOf str; };
@ -17,27 +36,31 @@ let
config = mkIf (elemType.name == "submodule") {
data._module.args.dagName = name;
};
});
maybeConvert = def:
}
);
maybeConvert =
def:
if hm.dag.isEntry def.value then
def.value
else
hm.dag.entryAnywhere (if def ? priority then
mkOrder def.priority def.value
else
def.value);
in mkOptionType {
hm.dag.entryAnywhere (if def ? priority then mkOrder def.priority def.value else def.value);
in
mkOptionType {
name = "dagEntryOf";
description = "DAG entry of ${elemType.description}";
# leave the checking to the submodule type
merge = loc: defs:
submoduleType.merge loc (map (def: {
merge =
loc: defs:
submoduleType.merge loc (
map (def: {
inherit (def) file;
value = maybeConvert def;
}) defs);
}) defs
);
};
in rec {
in
rec {
# A directed acyclic graph of some inner type.
#
# 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
# "actual" attribute name a new submodule argument is provided with
# the name `dagName`.
dagOf = elemType:
let attrEquivalent = types.attrsOf (dagEntryOf elemType);
in mkOptionType rec {
dagOf =
elemType:
let
attrEquivalent = types.attrsOf (dagEntryOf elemType);
in
mkOptionType rec {
name = "dagOf";
description = "DAG of ${elemType.description}";
inherit (attrEquivalent) check merge emptyValue;
getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "<name>" ]);
getSubModules = elemType.getSubModules;
substSubModules = m: dagOf (elemType.substSubModules m);
functor = (defaultFunctor name) // { wrapped = elemType; };
functor = (defaultFunctor name) // {
wrapped = 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
inherit (lib)
all concatMap foldl' getFiles getValues head isFunction literalExpression
mergeAttrs mergeDefaultOption mergeOneOption mergeOptions mkOption
mkOptionType showFiles showOption types;
all
concatMap
foldl'
getFiles
getValues
head
isFunction
literalExpression
mergeAttrs
mergeDefaultOption
mergeOneOption
mergeOptions
mkOption
mkOptionType
showFiles
showOption
types
;
typesDag = import ./types-dag.nix { inherit lib; };
@ -12,24 +30,30 @@ let
# must refer back to the type.
gvar = gvariant;
in rec {
in
rec {
inherit (typesDag) dagOf;
selectorFunction = mkOptionType {
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";
check = isFunction;
merge = _loc: defs: as: concatMap (select: select as) (getValues defs);
merge =
_loc: defs: as:
concatMap (select: select as) (getValues defs);
};
overlayFunction = mkOptionType {
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.";
check = isFunction;
merge = _loc: defs: self: super:
merge =
_loc: defs: self: super:
foldl' (res: def: mergeAttrs res (def.value self super)) { } defs;
};
@ -69,26 +93,32 @@ in rec {
name = "gvariant";
description = "GVariant value";
check = v: gvar.mkValue v != null;
merge = loc: defs:
merge =
loc: defs:
let
vdefs = map (d:
d // {
value =
if gvar.isGVariant d.value then d.value else gvar.mkValue d.value;
}) defs;
vdefs = map (
d:
d
// {
value = if gvar.isGVariant d.value then d.value else gvar.mkValue d.value;
}
) defs;
vals = map (d: d.value) vdefs;
defTypes = map (x: x.type) vals;
sameOrNull = x: y: if x == y then y else null;
# A bit naive to just check the first entry…
sharedDefType = foldl' sameOrNull (head defTypes) defTypes;
allChecked = all (x: check x) vals;
in if sharedDefType == null then
throw ("Cannot merge definitions of `${showOption loc}' with"
in
if sharedDefType == null then
throw (
"Cannot merge definitions of `${showOption loc}' with"
+ " mismatched GVariant types given in"
+ " ${showFiles (getFiles defs)}.")
+ " ${showFiles (getFiles defs)}."
)
else if gvar.isArray sharedDefType && allChecked then
gvar.mkValue ((types.listOf gvariant).merge loc
(map (d: d // { value = d.value.value; }) vdefs)) // {
gvar.mkValue ((types.listOf gvariant).merge loc (map (d: d // { value = d.value.value; }) vdefs))
// {
type = sharedDefType;
}
else if gvar.isTuple sharedDefType && allChecked then
@ -107,8 +137,10 @@ in rec {
mergeDefaultOption loc defs;
};
nushellValue = let
valueType = types.nullOr (types.oneOf [
nushellValue =
let
valueType = types.nullOr (
types.oneOf [
(lib.mkOptionType {
name = "nushell";
description = "Nushell inline value";
@ -120,14 +152,22 @@ in rec {
types.float
types.str
types.path
(types.attrsOf valueType // {
(
types.attrsOf valueType
// {
description = "attribute set of Nushell values";
descriptionClass = "name";
})
(types.listOf valueType // {
}
)
(
types.listOf valueType
// {
description = "list of Nushell values";
descriptionClass = "name";
})
]);
in valueType;
}
)
]
);
in
valueType;
}

View file

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

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
let
@ -9,7 +14,8 @@ let
inherit (config.home.version) release isReleaseBranch;
};
in {
in
{
options = {
manual.html.enable = lib.mkOption {
type = lib.types.bool;
@ -51,7 +57,10 @@ in {
config = {
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.json.enable [ docs.options.json ])
];

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,12 @@
# Adapted from Nixpkgs.
{ config, lib, pkgs, pkgsPath, ... }:
{
config,
lib,
pkgs,
pkgsPath,
...
}:
let
@ -8,16 +14,22 @@ let
optCall = f: x: if builtins.isFunction f then f x else f;
mergeConfig = lhs_: rhs_:
mergeConfig =
lhs_: rhs_:
let
lhs = optCall lhs_ { inherit pkgs; };
rhs = optCall rhs_ { inherit pkgs; };
in lhs // rhs // lib.optionalAttrs (lhs ? packageOverrides) {
packageOverrides = pkgs:
optCall lhs.packageOverrides pkgs
// optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs;
} // lib.optionalAttrs (lhs ? perlPackageOverrides) {
perlPackageOverrides = pkgs:
in
lhs
// rhs
// lib.optionalAttrs (lhs ? packageOverrides) {
packageOverrides =
pkgs:
optCall lhs.packageOverrides pkgs // optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs;
}
// lib.optionalAttrs (lhs ? perlPackageOverrides) {
perlPackageOverrides =
pkgs:
optCall lhs.perlPackageOverrides pkgs
// optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs;
};
@ -25,9 +37,12 @@ let
configType = lib.mkOptionType {
name = "nixpkgs-config";
description = "nixpkgs config";
check = x:
let traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false;
in traceXIfNot isConfig;
check =
x:
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) { };
};
@ -40,11 +55,14 @@ let
_pkgs = import pkgsPath (lib.filterAttrs (n: v: v != null) config.nixpkgs);
in {
in
{
options.nixpkgs = {
config = lib.mkOption {
default = null;
example = { allowBroken = true; };
example = {
allowBroken = true;
};
type = lib.types.nullOr configType;
description = ''
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 = lib.mkOverride lib.modules.defaultOverridePriority _pkgs;
pkgs_i686 =
if _pkgs.stdenv.isLinux && _pkgs.stdenv.hostPlatform.isx86 then
_pkgs.pkgsi686Linux
else
{ };
if _pkgs.stdenv.isLinux && _pkgs.stdenv.hostPlatform.isx86 then _pkgs.pkgsi686Linux else { };
};
};
}

View file

@ -1,18 +1,25 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
let
cfg = config.xsession.numlock;
in {
in
{
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 {
assertions = [
(lib.hm.assertions.assertPlatform "xsession.numlock" pkgs
lib.platforms.linux)
(lib.hm.assertions.assertPlatform "xsession.numlock" pkgs lib.platforms.linux)
];
systemd.user.services.numlockx = {
@ -28,7 +35,9 @@ in {
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;
in {
meta.maintainers = with lib.maintainers; [ rycee veehaitch ];
in
{
meta.maintainers = with lib.maintainers; [
rycee
veehaitch
];
options = {
pam.sessionVariables = lib.mkOption {
default = { };
type = lib.types.attrs;
example = { EDITOR = "vim"; };
example = {
EDITOR = "vim";
};
description = ''
Environment variables that will be set for the PAM session.
The variable values must be as described in
@ -24,13 +30,15 @@ in {
pam.yubico.authorizedYubiKeys = {
ids = lib.mkOption {
type = with lib.types;
type =
with lib.types;
let
yubiKeyId = addCheck str (s: lib.stringLength s == 12) // {
name = "yubiKeyId";
description = "string of length 12";
};
in listOf yubiKeyId;
in
listOf yubiKeyId;
default = [ ];
description = ''
List of authorized YubiKey token IDs. Refer to
@ -52,15 +60,17 @@ in {
config = lib.mkMerge [
(lib.mkIf (cfg.sessionVariables != { }) {
home.file.".pam_environment".text = lib.concatStringsSep "\n"
(lib.mapAttrsToList (n: v: ''${n} OVERRIDE="${toString v}"'')
cfg.sessionVariables) + "\n";
home.file.".pam_environment".text =
lib.concatStringsSep "\n" (
lib.mapAttrsToList (n: v: ''${n} OVERRIDE="${toString v}"'') cfg.sessionVariables
)
+ "\n";
})
(lib.mkIf (cfg.yubico.authorizedYubiKeys.ids != [ ]) {
home.file.${cfg.yubico.authorizedYubiKeys.path}.text =
lib.concatStringsSep ":"
([ config.home.username ] ++ cfg.yubico.authorizedYubiKeys.ids);
home.file.${cfg.yubico.authorizedYubiKeys.path}.text = lib.concatStringsSep ":" (
[ config.home.username ] ++ cfg.yubico.authorizedYubiKeys.ids
);
})
];
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,7 +5,8 @@ let
releaseInfo = lib.importJSON ../../release.json;
in {
in
{
options = {
home.stateVersion = lib.mkOption {
type = types.enum [
@ -44,11 +45,12 @@ in {
internal = true;
readOnly = true;
type = types.str;
default = let
default =
let
inherit (config.home.version) release revision;
suffix = lib.optionalString (revision != null)
"+${lib.substring 0 8 revision}";
in "${release}${suffix}";
suffix = lib.optionalString (revision != null) "+${lib.substring 0 8 revision}";
in
"${release}${suffix}";
example = "22.11+213a0629";
description = "The full Home Manager version.";
};
@ -76,11 +78,11 @@ in {
revision = lib.mkOption {
internal = true;
type = types.nullOr types.str;
default = let gitRepo = "${toString ./../..}/.git";
in if lib.pathIsGitRepo gitRepo then
lib.commitIdFromGitRepo gitRepo
else
null;
default =
let
gitRepo = "${toString ./../..}/.git";
in
if lib.pathIsGitRepo gitRepo then lib.commitIdFromGitRepo gitRepo else null;
description = ''
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 ];
options.programs = let
options.programs =
let
description = ''
Whether to enable integration with terminals using the VTE
library. This will let the terminal track the current working
directory.
'';
in {
in
{
bash.enableVteIntegration = lib.mkEnableOption "" // {
inherit description;
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,15 +1,34 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
attrsets generators literalExpression mapAttrs mkIf mkOption types;
attrsets
generators
literalExpression
mapAttrs
mkIf
mkOption
types
;
cfg = config.programs.aerc;
primitive = with types;
((type: either type (listOf type)) (nullOr (oneOf [ str int bool float ])))
primitive =
with types;
((type: either type (listOf type)) (
nullOr (oneOf [
str
int
bool
float
])
))
// {
description =
"values (null, bool, int, string, or float) or a list of values, that will be joined with a comma";
description = "values (null, bool, int, string, or float) or a list of values, that will be joined with a comma";
};
confSection = types.attrsOf primitive;
@ -19,18 +38,25 @@ let
sectionsOrLines = types.either types.lines confSections;
accounts = import ./aerc-accounts.nix {
inherit config pkgs lib confSection confSections;
inherit
config
pkgs
lib
confSection
confSections
;
};
aerc-accounts =
attrsets.filterAttrs (_: v: v.aerc.enable) config.accounts.email.accounts;
aerc-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"
else
"${config.xdg.configHome}/aerc";
in {
in
{
meta.maintainers = with lib.hm.maintainers; [ lukasngl ];
options.accounts.email.accounts = accounts.type;
@ -44,8 +70,7 @@ in {
extraAccounts = mkOption {
type = sectionsOrLines;
default = { };
example = literalExpression
''{ Work = { source = "maildir://~/Maildir/work"; }; }'';
example = literalExpression ''{ Work = { source = "maildir://~/Maildir/work"; }; }'';
description = ''
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);
toINI = conf: # quirk: global section is prepended w/o section heading
toINI =
conf: # quirk: global section is prepended w/o section heading
let
global = conf.global or { };
local = removeAttrs conf [ "global" ];
mkValueString = v:
mkValueString =
v:
if lib.isList v then # join with comma
lib.concatStringsSep ","
(map (generators.mkValueStringDefault { }) v)
lib.concatStringsSep "," (map (generators.mkValueStringDefault { }) v)
else
generators.mkValueStringDefault { } v;
mkKeyValue =
generators.mkKeyValueDefault { inherit mkValueString; } " = ";
in joinCfg [
mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } " = ";
in
joinCfg [
(generators.toKeyValue { inherit mkKeyValue; } global)
(generators.toINI { inherit mkKeyValue; } local)
];
mkINI = conf: if lib.isString conf then conf else toINI conf;
mkStyleset = attrsets.mapAttrs' (k: v:
let value = if lib.isString v then v else toINI { global = v; };
in {
mkStyleset = attrsets.mapAttrs' (
k: v:
let
value = if lib.isString v then v else toINI { global = v; };
in
{
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}";
value.text = v;
});
}
);
primaryAccount = 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;
joinContextual = contextual:
joinCfg (map mkINI (lib.attrValues contextual));
joinContextual = contextual: joinCfg (map mkINI (lib.attrValues contextual));
isRecursivelyEmpty = x:
if lib.isAttrs x then
lib.all (x: x == { } || isRecursivelyEmpty x) (lib.attrValues x)
else
false;
isRecursivelyEmpty =
x:
if lib.isAttrs x then lib.all (x: x == { } || isRecursivelyEmpty x) (lib.attrValues x) else false;
genAccountsConf = ((cfg.extraAccounts != "" && cfg.extraAccounts != { })
genAccountsConf = (
(cfg.extraAccounts != "" && cfg.extraAccounts != { })
|| !(isRecursivelyEmpty accountsExtraAccounts)
|| !(isRecursivelyEmpty primaryAccountAccounts));
|| !(isRecursivelyEmpty primaryAccountAccounts)
);
genAercConf = ((cfg.extraConfig != "" && cfg.extraConfig != { })
|| !(isRecursivelyEmpty accountsExtraConfig));
genAercConf = (
(cfg.extraConfig != "" && cfg.extraConfig != { }) || !(isRecursivelyEmpty accountsExtraConfig)
);
genBindsConf = ((cfg.extraBinds != "" && cfg.extraBinds != { })
|| !(isRecursivelyEmpty accountsExtraBinds));
genBindsConf = (
(cfg.extraBinds != "" && cfg.extraBinds != { }) || !(isRecursivelyEmpty accountsExtraBinds)
);
header = ''
# Generated by Home Manager.
'';
in mkIf cfg.enable {
warnings = if genAccountsConf
&& (cfg.extraConfig.general.unsafe-accounts-conf or false) == false then [''
in
mkIf cfg.enable {
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.
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).
@ -181,25 +221,32 @@ in {
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`.
This option is safe; if `passwordCommand` is properly set, no credentials will be written to the nix store.
''] else
''
]
else
[ ];
assertions = [{
assertion = let
extraConfigSections = (lib.unique (lib.flatten
(lib.mapAttrsToList (_: v: lib.attrNames v.aerc.extraConfig)
aerc-accounts)));
in extraConfigSections == [ ] || extraConfigSections == [ "ui" ];
assertions = [
{
assertion =
let
extraConfigSections = (
lib.unique (lib.flatten (lib.mapAttrsToList (_: v: lib.attrNames v.aerc.extraConfig) aerc-accounts))
);
in
extraConfigSections == [ ] || extraConfigSections == [ "ui" ];
message = ''
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
configuration to programs.aerc.extraConfig.
'';
}];
}
];
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
home.file = {
home.file =
{
"${configDir}/accounts.conf" = mkIf genAccountsConf {
text = joinCfg [
header
@ -224,6 +271,8 @@ in {
(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
inherit (lib) mkOption types;
cfg = config.programs.aerospace;
@ -6,22 +11,29 @@ let
tomlFormat = pkgs.formats.toml { };
# filterAttrsRecursive supporting lists, as well.
filterListAndAttrsRecursive = pred: set:
lib.listToAttrs (lib.concatMap (name:
let v = set.${name};
in if pred v then
filterListAndAttrsRecursive =
pred: set:
lib.listToAttrs (
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
else if lib.isList v then
(map (i:
if lib.isAttrs i then filterListAndAttrsRecursive pred i else i)
(lib.filter pred v))
(map (i: if lib.isAttrs i then filterListAndAttrsRecursive pred i else i) (lib.filter pred v))
else
v))
v
))
]
else
[ ]) (lib.attrNames set));
[ ]
) (lib.attrNames set)
);
filterNulls = filterListAndAttrsRecursive (v: v != null);
# Turns
@ -30,16 +42,22 @@ let
# {"if.foo" = "xxx"; "if.bar" = "yyy"}
# so that the correct TOML is generated for the
# on-window-detected table.
flattenConditions = attrs:
let conditions = attrs."if" or { };
in builtins.removeAttrs attrs [ "if" ]
// lib.concatMapAttrs (n: v: { "if.${n}" = v; }) conditions;
flattenConditions =
attrs:
let
conditions = attrs."if" or { };
in
builtins.removeAttrs attrs [ "if" ] // lib.concatMapAttrs (n: v: { "if.${n}" = v; }) conditions;
flattenOnWindowDetected = cfg:
let owd = cfg.on-window-detected or [ ];
in cfg // { on-window-detected = map flattenConditions owd; };
flattenOnWindowDetected =
cfg:
let
owd = cfg.on-window-detected or [ ];
in
cfg // { on-window-detected = map flattenConditions owd; };
in {
in
{
meta.maintainers = with lib.hm.maintainers; [ damidoug ];
options.programs.aerospace = {
@ -76,15 +94,12 @@ in {
enable-normalization-flatten-containers = mkOption {
type = types.bool;
default = true;
description =
''Containers that have only one child are "flattened".'';
description = ''Containers that have only one child are "flattened".'';
};
enable-normalization-opposite-orientation-for-nested-containers =
mkOption {
enable-normalization-opposite-orientation-for-nested-containers = mkOption {
type = types.bool;
default = true;
description =
"Containers that nest into each other must have opposite orientations.";
description = "Containers that nest into each other must have opposite orientations.";
};
accordion-padding = mkOption {
type = types.int;
@ -92,17 +107,25 @@ in {
description = "Padding between windows in an accordion container.";
};
default-root-container-layout = mkOption {
type = types.enum [ "tiles" "accordion" ];
type = types.enum [
"tiles"
"accordion"
];
default = "tiles";
description = "Default layout for the root container.";
};
default-root-container-orientation = mkOption {
type = types.enum [ "horizontal" "vertical" "auto" ];
type = types.enum [
"horizontal"
"vertical"
"auto"
];
default = "auto";
description = "Default orientation for the root container.";
};
on-window-detected = mkOption {
type = types.listOf (types.submodule {
type = types.listOf (
types.submodule {
options = {
"if" = mkOption {
type = types.submodule {
@ -120,20 +143,17 @@ in {
window-title-regex-substring = mkOption {
type = with types; nullOr str;
default = null;
description =
"Substring to match in the window title (optional).";
description = "Substring to match in the window title (optional).";
};
app-name-regex-substring = mkOption {
type = with types; nullOr str;
default = null;
description =
"Regex substring to match the app name (optional).";
description = "Regex substring to match the app name (optional).";
};
during-aerospace-startup = mkOption {
type = with types; nullOr bool;
default = null;
description =
"Whether to match during aerospace startup (optional).";
description = "Whether to match during aerospace startup (optional).";
};
};
};
@ -143,19 +163,27 @@ in {
check-further-callbacks = mkOption {
type = with types; nullOr bool;
default = null;
description =
"Whether to check further callbacks after this rule (optional).";
description = "Whether to check further callbacks after this rule (optional).";
};
run = mkOption {
type = with types; oneOf [ str (listOf str) ];
example = [ "move-node-to-workspace m" "resize-node" ];
description =
"Commands to execute when the conditions match (required).";
type =
with types;
oneOf [
str
(listOf str)
];
example = [
"move-node-to-workspace m"
"resize-node"
];
description = "Commands to execute when the conditions match (required).";
};
};
});
}
);
default = [ ];
example = [{
example = [
{
"if" = {
app-id = "Another.Cool.App";
workspace = "cool-workspace";
@ -164,14 +192,24 @@ in {
during-aerospace-startup = false;
};
check-further-callbacks = false;
run = [ "move-node-to-workspace m" "resize-node" ];
}];
description =
"Commands to run every time a new window is detected with optional conditions.";
run = [
"move-node-to-workspace m"
"resize-node"
];
}
];
description = "Commands to run every time a new window is detected with optional conditions.";
};
workspace-to-monitor-force-assignment = mkOption {
type = with types;
nullOr (attrsOf (oneOf [ int str (listOf str) ]));
type =
with types;
nullOr (
attrsOf (oneOf [
int
str
(listOf str)
])
);
default = null;
description = ''
Map workspaces to specific monitors.
@ -182,17 +220,18 @@ in {
"2" = "main"; # Main monitor.
"3" = "secondary"; # Secondary monitor (non-main).
"4" = "built-in"; # Built-in display.
"5" =
"^built-in retina display$"; # Regex for the built-in retina display.
"6" = [ "secondary" "dell" ]; # Match first pattern in the list.
"5" = "^built-in retina display$"; # Regex for the built-in retina display.
"6" = [
"secondary"
"dell"
]; # Match first pattern in the list.
};
};
on-focus-changed = mkOption {
type = with types; listOf str;
default = [ ];
example = [ "move-mouse monitor-lazy-center" ];
description =
"Commands to run every time focused window or workspace changes.";
description = "Commands to run every time focused window or workspace changes.";
};
on-focused-monitor-changed = mkOption {
type = with types; listOf str;
@ -210,7 +249,10 @@ in {
description = "Commands to run every time workspace changes.";
};
key-mapping.preset = mkOption {
type = types.enum [ "qwerty" "dvorak" ];
type = types.enum [
"qwerty"
"dvorak"
];
default = "qwerty";
description = "Keymapping preset.";
};
@ -243,15 +285,14 @@ in {
config = lib.mkIf cfg.enable {
assertions = [
(lib.hm.assertions.assertPlatform "programs.aerospace" pkgs
lib.platforms.darwin)
(lib.hm.assertions.assertPlatform "programs.aerospace" pkgs lib.platforms.darwin)
];
home = {
packages = lib.mkIf (cfg.package != null) [ cfg.package ];
file.".config/aerospace/aerospace.toml".source =
tomlFormat.generate "aerospace"
(filterNulls (flattenOnWindowDetected cfg.userSettings));
file.".config/aerospace/aerospace.toml".source = tomlFormat.generate "aerospace" (
filterNulls (flattenOnWindowDetected cfg.userSettings)
);
};
};
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,10 +1,16 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.awscli;
iniFormat = pkgs.formats.ini { };
in {
in
{
meta.maintainers = [ lib.maintainers.anthonyroussel ];
options.programs.awscli = {
@ -55,16 +61,12 @@ in {
config = lib.mkIf cfg.enable {
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
home.file."${config.home.homeDirectory}/.aws/config" =
lib.mkIf (cfg.settings != { }) {
source =
iniFormat.generate "aws-config-${config.home.username}" cfg.settings;
home.file."${config.home.homeDirectory}/.aws/config" = lib.mkIf (cfg.settings != { }) {
source = iniFormat.generate "aws-config-${config.home.username}" cfg.settings;
};
home.file."${config.home.homeDirectory}/.aws/credentials" =
lib.mkIf (cfg.credentials != { }) {
source = iniFormat.generate "aws-credentials-${config.home.username}"
cfg.credentials;
home.file."${config.home.homeDirectory}/.aws/credentials" = lib.mkIf (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
cfg = config.programs.bacon;
settingsFormat = pkgs.formats.toml { };
configDir = if pkgs.stdenv.isDarwin then
configDir =
if pkgs.stdenv.isDarwin then
"Library/Application Support/org.dystroy.bacon"
else
"${config.xdg.configHome}/bacon";
in {
in
{
meta.maintainers = [ lib.hm.maintainers.shimunn ];
options.programs.bacon = {
@ -23,7 +30,13 @@ in {
default = { };
example = {
jobs.default = {
command = [ "cargo" "build" "--all-features" "--color" "always" ];
command = [
"cargo"
"build"
"--all-features"
"--color"
"always"
];
need_stdout = true;
};
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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