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:
parent
5df48c4255
commit
cba2f9ce95
1051 changed files with 37028 additions and 26594 deletions
32
default.nix
32
default.nix
|
|
@ -1,4 +1,6 @@
|
||||||
{ pkgs ? import <nixpkgs> { } }:
|
{
|
||||||
|
pkgs ? import <nixpkgs> { },
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
path = builtins.path {
|
path = builtins.path {
|
||||||
|
|
@ -6,22 +8,26 @@ let
|
||||||
name = "home-manager-source";
|
name = "home-manager-source";
|
||||||
};
|
};
|
||||||
|
|
||||||
in rec {
|
in
|
||||||
docs = let releaseInfo = pkgs.lib.importJSON ./release.json;
|
rec {
|
||||||
in with import ./docs {
|
docs =
|
||||||
inherit pkgs;
|
let
|
||||||
inherit (releaseInfo) release isReleaseBranch;
|
releaseInfo = pkgs.lib.importJSON ./release.json;
|
||||||
}; {
|
in
|
||||||
|
with import ./docs {
|
||||||
|
inherit pkgs;
|
||||||
|
inherit (releaseInfo) release isReleaseBranch;
|
||||||
|
};
|
||||||
|
{
|
||||||
|
|
||||||
inherit manPages jsonModuleMaintainers;
|
inherit manPages jsonModuleMaintainers;
|
||||||
inherit (manual) html htmlOpenTool;
|
inherit (manual) html htmlOpenTool;
|
||||||
inherit (options) json;
|
inherit (options) json;
|
||||||
};
|
};
|
||||||
|
|
||||||
home-manager = pkgs.callPackage ./home-manager { inherit path; };
|
home-manager = pkgs.callPackage ./home-manager { inherit path; };
|
||||||
|
|
||||||
install =
|
install = pkgs.callPackage ./home-manager/install.nix { inherit home-manager; };
|
||||||
pkgs.callPackage ./home-manager/install.nix { inherit home-manager; };
|
|
||||||
|
|
||||||
nixos = import ./nixos;
|
nixos = import ./nixos;
|
||||||
lib = import ./lib { inherit (pkgs) lib; };
|
lib = import ./lib { inherit (pkgs) lib; };
|
||||||
|
|
|
||||||
232
docs/default.nix
232
docs/default.nix
|
|
@ -1,9 +1,12 @@
|
||||||
{ pkgs
|
{
|
||||||
|
pkgs,
|
||||||
|
|
||||||
# Note, this should be "the standard library" + HM extensions.
|
# Note, this should be "the standard library" + HM extensions.
|
||||||
, lib ? import ../modules/lib/stdlib-extended.nix pkgs.lib
|
lib ? import ../modules/lib/stdlib-extended.nix pkgs.lib,
|
||||||
|
|
||||||
, release, isReleaseBranch }:
|
release,
|
||||||
|
isReleaseBranch,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
|
|
@ -19,86 +22,124 @@ let
|
||||||
# Caveat: even if the package is reached by a different means, the
|
# Caveat: even if the package is reached by a different means, the
|
||||||
# path above will be shown and not e.g.
|
# path above will be shown and not e.g.
|
||||||
# `${config.services.foo.package}`.
|
# `${config.services.foo.package}`.
|
||||||
scrubDerivations = prefixPath: attrs:
|
scrubDerivations =
|
||||||
|
prefixPath: attrs:
|
||||||
let
|
let
|
||||||
scrubDerivation = name: value:
|
scrubDerivation =
|
||||||
let pkgAttrName = prefixPath + "." + name;
|
name: value:
|
||||||
in if lib.isAttrs value then
|
let
|
||||||
|
pkgAttrName = prefixPath + "." + name;
|
||||||
|
in
|
||||||
|
if lib.isAttrs value then
|
||||||
scrubDerivations pkgAttrName value
|
scrubDerivations pkgAttrName value
|
||||||
// lib.optionalAttrs (lib.isDerivation value) {
|
// lib.optionalAttrs (lib.isDerivation value) {
|
||||||
outPath = "\${${pkgAttrName}}";
|
outPath = "\${${pkgAttrName}}";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
value;
|
value;
|
||||||
in lib.mapAttrs scrubDerivation attrs;
|
in
|
||||||
|
lib.mapAttrs scrubDerivation attrs;
|
||||||
|
|
||||||
# Make sure the used package is scrubbed to avoid actually
|
# Make sure the used package is scrubbed to avoid actually
|
||||||
# instantiating derivations.
|
# instantiating derivations.
|
||||||
scrubbedPkgsModule = {
|
scrubbedPkgsModule = {
|
||||||
imports = [{
|
imports = [
|
||||||
_module.args = {
|
{
|
||||||
pkgs = lib.mkForce (scrubDerivations "pkgs" pkgs);
|
_module.args = {
|
||||||
pkgs_i686 = lib.mkForce { };
|
pkgs = lib.mkForce (scrubDerivations "pkgs" pkgs);
|
||||||
};
|
pkgs_i686 = lib.mkForce { };
|
||||||
}];
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
dontCheckDefinitions = { _module.check = false; };
|
dontCheckDefinitions = {
|
||||||
|
_module.check = false;
|
||||||
|
};
|
||||||
|
|
||||||
gitHubDeclaration = user: repo: subpath:
|
gitHubDeclaration =
|
||||||
let urlRef = if isReleaseBranch then "release-${release}" else "master";
|
user: repo: subpath:
|
||||||
in {
|
let
|
||||||
|
urlRef = if isReleaseBranch then "release-${release}" else "master";
|
||||||
|
in
|
||||||
|
{
|
||||||
url = "https://github.com/${user}/${repo}/blob/${urlRef}/${subpath}";
|
url = "https://github.com/${user}/${repo}/blob/${urlRef}/${subpath}";
|
||||||
name = "<${repo}/${subpath}>";
|
name = "<${repo}/${subpath}>";
|
||||||
};
|
};
|
||||||
|
|
||||||
hmPath = toString ./..;
|
hmPath = toString ./..;
|
||||||
|
|
||||||
buildOptionsDocs = args@{ modules, includeModuleSystemOptions ? true, ... }:
|
buildOptionsDocs =
|
||||||
|
args@{
|
||||||
|
modules,
|
||||||
|
includeModuleSystemOptions ? true,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
options = (lib.evalModules {
|
options =
|
||||||
inherit modules;
|
(lib.evalModules {
|
||||||
class = "homeManager";
|
inherit modules;
|
||||||
}).options;
|
class = "homeManager";
|
||||||
in pkgs.buildPackages.nixosOptionsDoc ({
|
}).options;
|
||||||
options = if includeModuleSystemOptions then
|
in
|
||||||
options
|
pkgs.buildPackages.nixosOptionsDoc (
|
||||||
else
|
{
|
||||||
builtins.removeAttrs options [ "_module" ];
|
options =
|
||||||
transformOptions = opt:
|
if includeModuleSystemOptions then options else builtins.removeAttrs options [ "_module" ];
|
||||||
opt // {
|
transformOptions =
|
||||||
# Clean up declaration sites to not refer to the Home Manager
|
opt:
|
||||||
# source tree.
|
opt
|
||||||
declarations = map (decl:
|
// {
|
||||||
if lib.hasPrefix hmPath (toString decl) then
|
# Clean up declaration sites to not refer to the Home Manager
|
||||||
gitHubDeclaration "nix-community" "home-manager"
|
# source tree.
|
||||||
(lib.removePrefix "/" (lib.removePrefix hmPath (toString decl)))
|
declarations = map (
|
||||||
else if decl == "lib/modules.nix" then
|
decl:
|
||||||
# TODO: handle this in a better way (may require upstream
|
if lib.hasPrefix hmPath (toString decl) then
|
||||||
# changes to nixpkgs)
|
gitHubDeclaration "nix-community" "home-manager" (
|
||||||
gitHubDeclaration "NixOS" "nixpkgs" decl
|
lib.removePrefix "/" (lib.removePrefix hmPath (toString decl))
|
||||||
else
|
)
|
||||||
decl) opt.declarations;
|
else if decl == "lib/modules.nix" then
|
||||||
};
|
# TODO: handle this in a better way (may require upstream
|
||||||
} // builtins.removeAttrs args [ "modules" "includeModuleSystemOptions" ]);
|
# changes to nixpkgs)
|
||||||
|
gitHubDeclaration "NixOS" "nixpkgs" decl
|
||||||
|
else
|
||||||
|
decl
|
||||||
|
) opt.declarations;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// builtins.removeAttrs args [
|
||||||
|
"modules"
|
||||||
|
"includeModuleSystemOptions"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
hmOptionsDocs = buildOptionsDocs {
|
hmOptionsDocs = buildOptionsDocs {
|
||||||
modules = import ../modules/modules.nix {
|
modules =
|
||||||
inherit lib pkgs;
|
import ../modules/modules.nix {
|
||||||
check = false;
|
inherit lib pkgs;
|
||||||
} ++ [ scrubbedPkgsModule ];
|
check = false;
|
||||||
|
}
|
||||||
|
++ [ scrubbedPkgsModule ];
|
||||||
variablelistId = "home-manager-options";
|
variablelistId = "home-manager-options";
|
||||||
};
|
};
|
||||||
|
|
||||||
nixosOptionsDocs = buildOptionsDocs {
|
nixosOptionsDocs = buildOptionsDocs {
|
||||||
modules = [ ../nixos scrubbedPkgsModule dontCheckDefinitions ];
|
modules = [
|
||||||
|
../nixos
|
||||||
|
scrubbedPkgsModule
|
||||||
|
dontCheckDefinitions
|
||||||
|
];
|
||||||
includeModuleSystemOptions = false;
|
includeModuleSystemOptions = false;
|
||||||
variablelistId = "nixos-options";
|
variablelistId = "nixos-options";
|
||||||
optionIdPrefix = "nixos-opt-";
|
optionIdPrefix = "nixos-opt-";
|
||||||
};
|
};
|
||||||
|
|
||||||
nixDarwinOptionsDocs = buildOptionsDocs {
|
nixDarwinOptionsDocs = buildOptionsDocs {
|
||||||
modules = [ ../nix-darwin scrubbedPkgsModule dontCheckDefinitions ];
|
modules = [
|
||||||
|
../nix-darwin
|
||||||
|
scrubbedPkgsModule
|
||||||
|
dontCheckDefinitions
|
||||||
|
];
|
||||||
includeModuleSystemOptions = false;
|
includeModuleSystemOptions = false;
|
||||||
variablelistId = "nix-darwin-options";
|
variablelistId = "nix-darwin-options";
|
||||||
optionIdPrefix = "nix-darwin-opt-";
|
optionIdPrefix = "nix-darwin-opt-";
|
||||||
|
|
@ -108,22 +149,26 @@ let
|
||||||
revision = "release-${release-config.release}";
|
revision = "release-${release-config.release}";
|
||||||
# Generate the `man home-configuration.nix` package
|
# Generate the `man home-configuration.nix` package
|
||||||
home-configuration-manual =
|
home-configuration-manual =
|
||||||
pkgs.runCommand "home-configuration-reference-manpage" {
|
pkgs.runCommand "home-configuration-reference-manpage"
|
||||||
nativeBuildInputs =
|
{
|
||||||
[ pkgs.buildPackages.installShellFiles pkgs.nixos-render-docs ];
|
nativeBuildInputs = [
|
||||||
allowedReferences = [ "out" ];
|
pkgs.buildPackages.installShellFiles
|
||||||
} ''
|
pkgs.nixos-render-docs
|
||||||
# Generate manpages.
|
];
|
||||||
mkdir -p $out/share/man/man5
|
allowedReferences = [ "out" ];
|
||||||
mkdir -p $out/share/man/man1
|
}
|
||||||
nixos-render-docs -j $NIX_BUILD_CORES options manpage \
|
''
|
||||||
--revision ${revision} \
|
# Generate manpages.
|
||||||
--header ${./home-configuration-nix-header.5} \
|
mkdir -p $out/share/man/man5
|
||||||
--footer ${./home-configuration-nix-footer.5} \
|
mkdir -p $out/share/man/man1
|
||||||
${hmOptionsDocs.optionsJSON}/share/doc/nixos/options.json \
|
nixos-render-docs -j $NIX_BUILD_CORES options manpage \
|
||||||
$out/share/man/man5/home-configuration.nix.5
|
--revision ${revision} \
|
||||||
cp ${./home-manager.1} $out/share/man/man1/home-manager.1
|
--header ${./home-configuration-nix-header.5} \
|
||||||
'';
|
--footer ${./home-configuration-nix-footer.5} \
|
||||||
|
${hmOptionsDocs.optionsJSON}/share/doc/nixos/options.json \
|
||||||
|
$out/share/man/man5/home-configuration.nix.5
|
||||||
|
cp ${./home-manager.1} $out/share/man/man1/home-manager.1
|
||||||
|
'';
|
||||||
# Generate the HTML manual pages
|
# Generate the HTML manual pages
|
||||||
home-manager-manual = pkgs.callPackage ./home-manager-manual.nix {
|
home-manager-manual = pkgs.callPackage ./home-manager-manual.nix {
|
||||||
home-manager-options = {
|
home-manager-options = {
|
||||||
|
|
@ -135,22 +180,26 @@ let
|
||||||
};
|
};
|
||||||
html = home-manager-manual;
|
html = home-manager-manual;
|
||||||
htmlOpenTool = pkgs.callPackage ./html-open-tool.nix { } { inherit html; };
|
htmlOpenTool = pkgs.callPackage ./html-open-tool.nix { } { inherit html; };
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
# TODO: Use `hmOptionsDocs.optionsJSON` directly once upstream
|
# TODO: Use `hmOptionsDocs.optionsJSON` directly once upstream
|
||||||
# `nixosOptionsDoc` is more customizable.
|
# `nixosOptionsDoc` is more customizable.
|
||||||
json = pkgs.runCommand "options.json" {
|
json =
|
||||||
meta.description = "List of Home Manager options in JSON format";
|
pkgs.runCommand "options.json"
|
||||||
} ''
|
{
|
||||||
mkdir -p $out/{share/doc,nix-support}
|
meta.description = "List of Home Manager options in JSON format";
|
||||||
cp -a ${hmOptionsDocs.optionsJSON}/share/doc/nixos $out/share/doc/home-manager
|
}
|
||||||
substitute \
|
''
|
||||||
${hmOptionsDocs.optionsJSON}/nix-support/hydra-build-products \
|
mkdir -p $out/{share/doc,nix-support}
|
||||||
$out/nix-support/hydra-build-products \
|
cp -a ${hmOptionsDocs.optionsJSON}/share/doc/nixos $out/share/doc/home-manager
|
||||||
--replace-fail \
|
substitute \
|
||||||
'${hmOptionsDocs.optionsJSON}/share/doc/nixos' \
|
${hmOptionsDocs.optionsJSON}/nix-support/hydra-build-products \
|
||||||
"$out/share/doc/home-manager"
|
$out/nix-support/hydra-build-products \
|
||||||
'';
|
--replace-fail \
|
||||||
|
'${hmOptionsDocs.optionsJSON}/share/doc/nixos' \
|
||||||
|
"$out/share/doc/home-manager"
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
manPages = home-configuration-manual;
|
manPages = home-configuration-manual;
|
||||||
|
|
@ -158,13 +207,18 @@ in {
|
||||||
manual = { inherit html htmlOpenTool; };
|
manual = { inherit html htmlOpenTool; };
|
||||||
|
|
||||||
# Unstable, mainly for CI.
|
# Unstable, mainly for CI.
|
||||||
jsonModuleMaintainers = pkgs.writeText "hm-module-maintainers.json" (let
|
jsonModuleMaintainers = pkgs.writeText "hm-module-maintainers.json" (
|
||||||
result = lib.evalModules {
|
let
|
||||||
modules = import ../modules/modules.nix {
|
result = lib.evalModules {
|
||||||
inherit lib pkgs;
|
modules =
|
||||||
check = false;
|
import ../modules/modules.nix {
|
||||||
} ++ [ scrubbedPkgsModule ];
|
inherit lib pkgs;
|
||||||
class = "homeManager";
|
check = false;
|
||||||
};
|
}
|
||||||
in builtins.toJSON result.config.meta.maintainers);
|
++ [ scrubbedPkgsModule ];
|
||||||
|
class = "homeManager";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
builtins.toJSON result.config.meta.maintainers
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,12 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, scss-reset }:
|
outputs =
|
||||||
|
{
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
scss-reset,
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
supportedSystems = [
|
supportedSystems = [
|
||||||
"aarch64-darwin"
|
"aarch64-darwin"
|
||||||
|
|
@ -28,7 +33,12 @@
|
||||||
p-build = pkgs.writeShellScriptBin "p-build" ''
|
p-build = pkgs.writeShellScriptBin "p-build" ''
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
export PATH=${lib.makeBinPath [ pkgs.coreutils pkgs.rsass ]}
|
export PATH=${
|
||||||
|
lib.makeBinPath [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.rsass
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
tmpfile=$(mktemp -d)
|
tmpfile=$(mktemp -d)
|
||||||
trap "rm -r $tmpfile" EXIT
|
trap "rm -r $tmpfile" EXIT
|
||||||
|
|
@ -42,20 +52,25 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
releaseInfo = lib.importJSON ../release.json;
|
releaseInfo = lib.importJSON ../release.json;
|
||||||
in {
|
in
|
||||||
devShells = forAllSystems (system:
|
{
|
||||||
|
devShells = forAllSystems (
|
||||||
|
system:
|
||||||
let
|
let
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
fpkgs = flakePkgs pkgs;
|
fpkgs = flakePkgs pkgs;
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell {
|
||||||
name = "hm-docs";
|
name = "hm-docs";
|
||||||
packages = [ fpkgs.p-build ];
|
packages = [ fpkgs.p-build ];
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
# Expose the docs outputs
|
# Expose the docs outputs
|
||||||
packages = forAllSystems (system:
|
packages = forAllSystems (
|
||||||
|
system:
|
||||||
let
|
let
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
docs = import ./default.nix {
|
docs = import ./default.nix {
|
||||||
|
|
@ -63,10 +78,12 @@
|
||||||
release = releaseInfo.release;
|
release = releaseInfo.release;
|
||||||
isReleaseBranch = releaseInfo.isReleaseBranch;
|
isReleaseBranch = releaseInfo.isReleaseBranch;
|
||||||
};
|
};
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
inherit (docs) manPages jsonModuleMaintainers;
|
inherit (docs) manPages jsonModuleMaintainers;
|
||||||
inherit (docs.manual) html htmlOpenTool;
|
inherit (docs.manual) html htmlOpenTool;
|
||||||
inherit (docs.options) json;
|
inherit (docs.options) json;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,15 @@
|
||||||
{ stdenv, lib, documentation-highlighter, revision, home-manager-options
|
{
|
||||||
, nixos-render-docs }:
|
stdenv,
|
||||||
let outputPath = "share/doc/home-manager";
|
lib,
|
||||||
in stdenv.mkDerivation {
|
documentation-highlighter,
|
||||||
|
revision,
|
||||||
|
home-manager-options,
|
||||||
|
nixos-render-docs,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
outputPath = "share/doc/home-manager";
|
||||||
|
in
|
||||||
|
stdenv.mkDerivation {
|
||||||
name = "home-manager-manual";
|
name = "home-manager-manual";
|
||||||
|
|
||||||
nativeBuildInputs = [ nixos-render-docs ];
|
nativeBuildInputs = [ nixos-render-docs ];
|
||||||
|
|
@ -61,5 +69,7 @@ in stdenv.mkDerivation {
|
||||||
|
|
||||||
passthru = { inherit home-manager-options; };
|
passthru = { inherit home-manager-options; };
|
||||||
|
|
||||||
meta = { maintainers = [ lib.maintainers.considerate ]; };
|
meta = {
|
||||||
|
maintainers = [ lib.maintainers.considerate ];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,14 @@
|
||||||
{ writeShellScriptBin, makeDesktopItem, symlinkJoin }:
|
{
|
||||||
{ html, pathName ? "home-manager", projectName ? pathName
|
writeShellScriptBin,
|
||||||
, name ? "${pathName}-help" }:
|
makeDesktopItem,
|
||||||
|
symlinkJoin,
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
html,
|
||||||
|
pathName ? "home-manager",
|
||||||
|
projectName ? pathName,
|
||||||
|
name ? "${pathName}-help",
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
helpScript = writeShellScriptBin name ''
|
helpScript = writeShellScriptBin name ''
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
@ -30,7 +38,11 @@ let
|
||||||
exec = "${helpScript}/bin/${name}";
|
exec = "${helpScript}/bin/${name}";
|
||||||
categories = [ "System" ];
|
categories = [ "System" ];
|
||||||
};
|
};
|
||||||
in symlinkJoin {
|
in
|
||||||
|
symlinkJoin {
|
||||||
inherit name;
|
inherit name;
|
||||||
paths = [ helpScript desktopItem ];
|
paths = [
|
||||||
|
helpScript
|
||||||
|
desktopItem
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,18 @@
|
||||||
{ lib, flake-parts-lib, moduleLocation, ... }:
|
{
|
||||||
let inherit (lib) toString mapAttrs mkOption types;
|
lib,
|
||||||
in {
|
flake-parts-lib,
|
||||||
|
moduleLocation,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
toString
|
||||||
|
mapAttrs
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
flake = flake-parts-lib.mkSubmoduleOptions {
|
flake = flake-parts-lib.mkSubmoduleOptions {
|
||||||
homeConfigurations = mkOption {
|
homeConfigurations = mkOption {
|
||||||
|
|
@ -17,11 +29,13 @@ in {
|
||||||
homeModules = mkOption {
|
homeModules = mkOption {
|
||||||
type = types.lazyAttrsOf types.deferredModule;
|
type = types.lazyAttrsOf types.deferredModule;
|
||||||
default = { };
|
default = { };
|
||||||
apply = mapAttrs (k: v: {
|
apply = mapAttrs (
|
||||||
_class = "homeManager";
|
k: v: {
|
||||||
_file = "${toString moduleLocation}#homeModules.${k}";
|
_class = "homeManager";
|
||||||
imports = [ v ];
|
_file = "${toString moduleLocation}#homeModules.${k}";
|
||||||
});
|
imports = [ v ];
|
||||||
|
}
|
||||||
|
);
|
||||||
description = ''
|
description = ''
|
||||||
Home Manager modules.
|
Home Manager modules.
|
||||||
|
|
||||||
|
|
|
||||||
82
flake.nix
82
flake.nix
|
|
@ -10,7 +10,13 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, treefmt-nix, ... }:
|
outputs =
|
||||||
|
{
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
treefmt-nix,
|
||||||
|
...
|
||||||
|
}:
|
||||||
{
|
{
|
||||||
nixosModules = rec {
|
nixosModules = rec {
|
||||||
home-manager = ./nixos;
|
home-manager = ./nixos;
|
||||||
|
|
@ -44,42 +50,50 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
lib = import ./lib { inherit (nixpkgs) lib; };
|
lib = import ./lib { inherit (nixpkgs) lib; };
|
||||||
} // (let
|
}
|
||||||
forAllSystems = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed;
|
// (
|
||||||
|
let
|
||||||
|
forAllSystems = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed;
|
||||||
|
|
||||||
treefmtEval = forAllSystems (
|
treefmtEval = forAllSystems (
|
||||||
system:
|
system:
|
||||||
treefmt-nix.lib.evalModule nixpkgs.legacyPackages.${system} {
|
treefmt-nix.lib.evalModule nixpkgs.legacyPackages.${system} {
|
||||||
# Formatting configuration
|
# Formatting configuration
|
||||||
programs = {
|
programs = {
|
||||||
nixfmt.enable = true;
|
nixfmt.enable = true;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
checks = forAllSystems (system: {
|
||||||
|
formatting = treefmtEval.${system}.config.build.check self;
|
||||||
});
|
});
|
||||||
in {
|
|
||||||
checks = forAllSystems (system: {
|
|
||||||
formatting = treefmtEval.${system}.config.build.check self;
|
|
||||||
});
|
|
||||||
|
|
||||||
formatter = forAllSystems (system: treefmtEval.${system}.config.build.wrapper);
|
formatter = forAllSystems (system: treefmtEval.${system}.config.build.wrapper);
|
||||||
|
|
||||||
packages = forAllSystems (system:
|
packages = forAllSystems (
|
||||||
let
|
system:
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
let
|
||||||
releaseInfo = nixpkgs.lib.importJSON ./release.json;
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
docs = import ./docs {
|
releaseInfo = nixpkgs.lib.importJSON ./release.json;
|
||||||
inherit pkgs;
|
docs = import ./docs {
|
||||||
inherit (releaseInfo) release isReleaseBranch;
|
inherit pkgs;
|
||||||
};
|
inherit (releaseInfo) release isReleaseBranch;
|
||||||
hmPkg = pkgs.callPackage ./home-manager { path = "${self}"; };
|
};
|
||||||
in {
|
hmPkg = pkgs.callPackage ./home-manager { path = "${self}"; };
|
||||||
default = hmPkg;
|
in
|
||||||
home-manager = hmPkg;
|
{
|
||||||
|
default = hmPkg;
|
||||||
|
home-manager = hmPkg;
|
||||||
|
|
||||||
docs-html = docs.manual.html;
|
docs-html = docs.manual.html;
|
||||||
docs-htmlOpenTool = docs.manual.htmlOpenTool;
|
docs-htmlOpenTool = docs.manual.htmlOpenTool;
|
||||||
docs-json = docs.options.json;
|
docs-json = docs.options.json;
|
||||||
docs-jsonModuleMaintainers = docs.jsonModuleMaintainers;
|
docs-jsonModuleMaintainers = docs.jsonModuleMaintainers;
|
||||||
docs-manpages = docs.manPages;
|
docs-manpages = docs.manPages;
|
||||||
});
|
}
|
||||||
});
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,46 +2,70 @@
|
||||||
# file is considered internal and the exported fields may change without
|
# file is considered internal and the exported fields may change without
|
||||||
# warning.
|
# warning.
|
||||||
|
|
||||||
{ newsJsonFile, newsReadIdsFile ? null }:
|
{
|
||||||
|
newsJsonFile,
|
||||||
|
newsReadIdsFile ? null,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (builtins)
|
inherit (builtins)
|
||||||
concatStringsSep filter hasAttr isString length readFile replaceStrings sort
|
concatStringsSep
|
||||||
split;
|
filter
|
||||||
|
hasAttr
|
||||||
|
isString
|
||||||
|
length
|
||||||
|
readFile
|
||||||
|
replaceStrings
|
||||||
|
sort
|
||||||
|
split
|
||||||
|
;
|
||||||
|
|
||||||
newsJson = builtins.fromJSON (builtins.readFile newsJsonFile);
|
newsJson = builtins.fromJSON (builtins.readFile newsJsonFile);
|
||||||
|
|
||||||
# Sorted and relevant entries.
|
# Sorted and relevant entries.
|
||||||
relevantEntries =
|
relevantEntries = sort (a: b: a.time > b.time) (filter (e: e.condition) newsJson.entries);
|
||||||
sort (a: b: a.time > b.time) (filter (e: e.condition) newsJson.entries);
|
|
||||||
|
|
||||||
newsReadIds = if newsReadIdsFile == null then
|
newsReadIds =
|
||||||
{ }
|
if newsReadIdsFile == null then
|
||||||
else
|
{ }
|
||||||
let ids = filter isString (split "\n" (readFile newsReadIdsFile));
|
else
|
||||||
in builtins.listToAttrs (map (id: {
|
let
|
||||||
name = id;
|
ids = filter isString (split "\n" (readFile newsReadIdsFile));
|
||||||
value = null;
|
in
|
||||||
}) ids);
|
builtins.listToAttrs (
|
||||||
|
map (id: {
|
||||||
|
name = id;
|
||||||
|
value = null;
|
||||||
|
}) ids
|
||||||
|
);
|
||||||
|
|
||||||
newsIsRead = entry: hasAttr entry.id newsReadIds;
|
newsIsRead = entry: hasAttr entry.id newsReadIds;
|
||||||
|
|
||||||
newsUnread = let pred = entry: entry.condition && !newsIsRead entry;
|
newsUnread =
|
||||||
in filter pred relevantEntries;
|
let
|
||||||
|
pred = entry: entry.condition && !newsIsRead entry;
|
||||||
|
in
|
||||||
|
filter pred relevantEntries;
|
||||||
|
|
||||||
prettyTime = t: replaceStrings [ "T" "+00:00" ] [ " " "" ] t;
|
prettyTime = t: replaceStrings [ "T" "+00:00" ] [ " " "" ] t;
|
||||||
|
|
||||||
layoutNews = entries:
|
layoutNews =
|
||||||
|
entries:
|
||||||
let
|
let
|
||||||
mkTextEntry = entry:
|
mkTextEntry =
|
||||||
let flag = if newsIsRead entry then "read" else "unread";
|
entry:
|
||||||
in ''
|
let
|
||||||
|
flag = if newsIsRead entry then "read" else "unread";
|
||||||
|
in
|
||||||
|
''
|
||||||
* ${prettyTime entry.time} [${flag}]
|
* ${prettyTime entry.time} [${flag}]
|
||||||
|
|
||||||
${replaceStrings [ "\n" ] [ "\n " ] entry.message}
|
${replaceStrings [ "\n" ] [ "\n " ] entry.message}
|
||||||
'';
|
'';
|
||||||
in concatStringsSep "\n\n" (map mkTextEntry entries);
|
in
|
||||||
in {
|
concatStringsSep "\n\n" (map mkTextEntry entries);
|
||||||
|
in
|
||||||
|
{
|
||||||
meta = {
|
meta = {
|
||||||
numUnread = length newsUnread;
|
numUnread = length newsUnread;
|
||||||
display = newsJson.display;
|
display = newsJson.display;
|
||||||
|
|
|
||||||
|
|
@ -1,64 +1,79 @@
|
||||||
{ runCommand, lib, bash, callPackage, coreutils, findutils, gettext, gnused, jq
|
{
|
||||||
, less, ncurses, inetutils
|
runCommand,
|
||||||
# used for pkgs.path for nixos-option
|
lib,
|
||||||
, pkgs
|
bash,
|
||||||
|
callPackage,
|
||||||
|
coreutils,
|
||||||
|
findutils,
|
||||||
|
gettext,
|
||||||
|
gnused,
|
||||||
|
jq,
|
||||||
|
less,
|
||||||
|
ncurses,
|
||||||
|
inetutils,
|
||||||
|
# used for pkgs.path for nixos-option
|
||||||
|
pkgs,
|
||||||
|
|
||||||
# Path to use as the Home Manager channel.
|
# Path to use as the Home Manager channel.
|
||||||
, path ? null }:
|
path ? null,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
pathStr = if path == null then "" else path;
|
pathStr = if path == null then "" else path;
|
||||||
|
|
||||||
nixos-option = pkgs.nixos-option or (callPackage
|
nixos-option =
|
||||||
(pkgs.path + "/nixos/modules/installer/tools/nixos-option") { });
|
pkgs.nixos-option or (callPackage (pkgs.path + "/nixos/modules/installer/tools/nixos-option") { });
|
||||||
|
|
||||||
in runCommand "home-manager" {
|
in
|
||||||
preferLocalBuild = true;
|
runCommand "home-manager"
|
||||||
nativeBuildInputs = [ gettext ];
|
{
|
||||||
meta = {
|
preferLocalBuild = true;
|
||||||
mainProgram = "home-manager";
|
nativeBuildInputs = [ gettext ];
|
||||||
description = "A user environment configurator";
|
meta = {
|
||||||
maintainers = [ lib.maintainers.rycee ];
|
mainProgram = "home-manager";
|
||||||
platforms = lib.platforms.unix;
|
description = "A user environment configurator";
|
||||||
license = lib.licenses.mit;
|
maintainers = [ lib.maintainers.rycee ];
|
||||||
};
|
platforms = lib.platforms.unix;
|
||||||
} ''
|
license = lib.licenses.mit;
|
||||||
install -v -D -m755 ${./home-manager} $out/bin/home-manager
|
};
|
||||||
|
}
|
||||||
|
''
|
||||||
|
install -v -D -m755 ${./home-manager} $out/bin/home-manager
|
||||||
|
|
||||||
substituteInPlace $out/bin/home-manager \
|
substituteInPlace $out/bin/home-manager \
|
||||||
--subst-var-by bash "${bash}" \
|
--subst-var-by bash "${bash}" \
|
||||||
--subst-var-by DEP_PATH "${
|
--subst-var-by DEP_PATH "${
|
||||||
lib.makeBinPath [
|
lib.makeBinPath [
|
||||||
coreutils
|
coreutils
|
||||||
findutils
|
findutils
|
||||||
gettext
|
gettext
|
||||||
gnused
|
gnused
|
||||||
jq
|
jq
|
||||||
less
|
less
|
||||||
ncurses
|
ncurses
|
||||||
nixos-option
|
nixos-option
|
||||||
inetutils # for `hostname`
|
inetutils # for `hostname`
|
||||||
]
|
]
|
||||||
}" \
|
}" \
|
||||||
--subst-var-by HOME_MANAGER_LIB '${../lib/bash/home-manager.sh}' \
|
--subst-var-by HOME_MANAGER_LIB '${../lib/bash/home-manager.sh}' \
|
||||||
--subst-var-by HOME_MANAGER_PATH '${pathStr}' \
|
--subst-var-by HOME_MANAGER_PATH '${pathStr}' \
|
||||||
--subst-var-by OUT "$out"
|
--subst-var-by OUT "$out"
|
||||||
|
|
||||||
install -D -m755 ${./completion.bash} \
|
install -D -m755 ${./completion.bash} \
|
||||||
$out/share/bash-completion/completions/home-manager
|
$out/share/bash-completion/completions/home-manager
|
||||||
install -D -m755 ${./completion.zsh} \
|
install -D -m755 ${./completion.zsh} \
|
||||||
$out/share/zsh/site-functions/_home-manager
|
$out/share/zsh/site-functions/_home-manager
|
||||||
install -D -m755 ${./completion.fish} \
|
install -D -m755 ${./completion.fish} \
|
||||||
$out/share/fish/vendor_completions.d/home-manager.fish
|
$out/share/fish/vendor_completions.d/home-manager.fish
|
||||||
|
|
||||||
install -D -m755 ${../lib/bash/home-manager.sh} \
|
install -D -m755 ${../lib/bash/home-manager.sh} \
|
||||||
"$out/share/bash/home-manager.sh"
|
"$out/share/bash/home-manager.sh"
|
||||||
|
|
||||||
for path in ${./po}/*.po; do
|
for path in ${./po}/*.po; do
|
||||||
lang="''${path##*/}"
|
lang="''${path##*/}"
|
||||||
lang="''${lang%%.*}"
|
lang="''${lang%%.*}"
|
||||||
mkdir -p "$out/share/locale/$lang/LC_MESSAGES"
|
mkdir -p "$out/share/locale/$lang/LC_MESSAGES"
|
||||||
msgfmt -o "$out/share/locale/$lang/LC_MESSAGES/home-manager.mo" "$path"
|
msgfmt -o "$out/share/locale/$lang/LC_MESSAGES/home-manager.mo" "$path"
|
||||||
done
|
done
|
||||||
''
|
''
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,31 @@
|
||||||
{ pkgs ? import <nixpkgs> { }, confPath, confAttr ? null, check ? true
|
{
|
||||||
, newsReadIdsFile ? null }:
|
pkgs ? import <nixpkgs> { },
|
||||||
|
confPath,
|
||||||
|
confAttr ? null,
|
||||||
|
check ? true,
|
||||||
|
newsReadIdsFile ? null,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (pkgs.lib)
|
inherit (pkgs.lib)
|
||||||
concatMapStringsSep fileContents filter length optionalString removeSuffix
|
concatMapStringsSep
|
||||||
replaceStrings splitString;
|
fileContents
|
||||||
|
filter
|
||||||
|
length
|
||||||
|
optionalString
|
||||||
|
removeSuffix
|
||||||
|
replaceStrings
|
||||||
|
splitString
|
||||||
|
;
|
||||||
|
|
||||||
env = import ../modules {
|
env = import ../modules {
|
||||||
configuration = if confAttr == "" || confAttr == null then
|
configuration =
|
||||||
confPath
|
if confAttr == "" || confAttr == null then confPath else (import confPath).${confAttr};
|
||||||
else
|
|
||||||
(import confPath).${confAttr};
|
|
||||||
pkgs = pkgs;
|
pkgs = pkgs;
|
||||||
check = check;
|
check = check;
|
||||||
};
|
};
|
||||||
|
|
||||||
in { inherit (env) activationPackage config; }
|
in
|
||||||
|
{
|
||||||
|
inherit (env) activationPackage config;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,16 @@ let
|
||||||
source ${home-manager}/share/bash/home-manager.sh
|
source ${home-manager}/share/bash/home-manager.sh
|
||||||
'';
|
'';
|
||||||
|
|
||||||
in runCommand "home-manager-install" {
|
in
|
||||||
propagatedBuildInputs = [ home-manager ];
|
runCommand "home-manager-install"
|
||||||
preferLocalBuild = true;
|
{
|
||||||
shellHookOnly = true;
|
propagatedBuildInputs = [ home-manager ];
|
||||||
shellHook = "exec ${home-manager}/bin/home-manager init --switch --no-flake";
|
preferLocalBuild = true;
|
||||||
} ''
|
shellHookOnly = true;
|
||||||
${hmBashLibInit}
|
shellHook = "exec ${home-manager}/bin/home-manager init --switch --no-flake";
|
||||||
_iError 'This derivation is not buildable, please run it using nix-shell.'
|
}
|
||||||
exit 1
|
''
|
||||||
''
|
${hmBashLibInit}
|
||||||
|
_iError 'This derivation is not buildable, please run it using nix-shell.'
|
||||||
|
exit 1
|
||||||
|
''
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
{ lib }: {
|
{ lib }:
|
||||||
|
{
|
||||||
hm = (import ../modules/lib/stdlib-extended.nix lib).hm;
|
hm = (import ../modules/lib/stdlib-extended.nix lib).hm;
|
||||||
homeManagerConfiguration = { modules ? [ ], pkgs, lib ? pkgs.lib
|
homeManagerConfiguration =
|
||||||
, extraSpecialArgs ? { }, check ? true
|
{
|
||||||
|
modules ? [ ],
|
||||||
|
pkgs,
|
||||||
|
lib ? pkgs.lib,
|
||||||
|
extraSpecialArgs ? { },
|
||||||
|
check ? true,
|
||||||
# Deprecated:
|
# Deprecated:
|
||||||
, configuration ? null, extraModules ? null, stateVersion ? null
|
configuration ? null,
|
||||||
, username ? null, homeDirectory ? null, system ? null }@args:
|
extraModules ? null,
|
||||||
|
stateVersion ? null,
|
||||||
|
username ? null,
|
||||||
|
homeDirectory ? null,
|
||||||
|
system ? null,
|
||||||
|
}@args:
|
||||||
let
|
let
|
||||||
msgForRemovedArg = ''
|
msgForRemovedArg = ''
|
||||||
The 'homeManagerConfiguration' arguments
|
The 'homeManagerConfiguration' arguments
|
||||||
|
|
@ -20,7 +31,8 @@
|
||||||
'modules'. See the 22.11 release notes for more: https://nix-community.github.io/home-manager/release-notes.xhtml#sec-release-22.11-highlights
|
'modules'. See the 22.11 release notes for more: https://nix-community.github.io/home-manager/release-notes.xhtml#sec-release-22.11-highlights
|
||||||
'';
|
'';
|
||||||
|
|
||||||
throwForRemovedArgs = v:
|
throwForRemovedArgs =
|
||||||
|
v:
|
||||||
let
|
let
|
||||||
used = builtins.filter (n: (args.${n} or null) != null) [
|
used = builtins.filter (n: (args.${n} or null) != null) [
|
||||||
"configuration"
|
"configuration"
|
||||||
|
|
@ -30,20 +42,34 @@
|
||||||
"extraModules"
|
"extraModules"
|
||||||
"system"
|
"system"
|
||||||
];
|
];
|
||||||
msg = msgForRemovedArg + ''
|
msg =
|
||||||
|
msgForRemovedArg
|
||||||
|
+ ''
|
||||||
|
|
||||||
|
|
||||||
Deprecated args passed: '' + builtins.concatStringsSep " " used;
|
Deprecated args passed: ''
|
||||||
in lib.throwIf (used != [ ]) msg v;
|
+ builtins.concatStringsSep " " used;
|
||||||
|
in
|
||||||
|
lib.throwIf (used != [ ]) msg v;
|
||||||
|
|
||||||
in throwForRemovedArgs (import ../modules {
|
in
|
||||||
inherit pkgs lib check extraSpecialArgs;
|
throwForRemovedArgs (
|
||||||
configuration = { ... }: {
|
import ../modules {
|
||||||
imports = modules ++ [{ programs.home-manager.path = "${../.}"; }];
|
inherit
|
||||||
nixpkgs = {
|
pkgs
|
||||||
config = lib.mkDefault pkgs.config;
|
lib
|
||||||
inherit (pkgs) overlays;
|
check
|
||||||
};
|
extraSpecialArgs
|
||||||
};
|
;
|
||||||
});
|
configuration =
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
imports = modules ++ [ { programs.home-manager.path = "${../.}"; } ];
|
||||||
|
nixpkgs = {
|
||||||
|
config = lib.mkDefault pkgs.config;
|
||||||
|
inherit (pkgs) overlays;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,19 +4,22 @@ let
|
||||||
|
|
||||||
cfg = config.accounts.calendar;
|
cfg = config.accounts.calendar;
|
||||||
|
|
||||||
localModule = name:
|
localModule =
|
||||||
|
name:
|
||||||
types.submodule {
|
types.submodule {
|
||||||
options = {
|
options = {
|
||||||
path = mkOption {
|
path = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "${cfg.basePath}/${name}";
|
default = "${cfg.basePath}/${name}";
|
||||||
defaultText =
|
defaultText = lib.literalExpression "‹accounts.calendar.basePath›/‹name›";
|
||||||
lib.literalExpression "‹accounts.calendar.basePath›/‹name›";
|
|
||||||
description = "The path of the storage.";
|
description = "The path of the storage.";
|
||||||
};
|
};
|
||||||
|
|
||||||
type = mkOption {
|
type = mkOption {
|
||||||
type = types.enum [ "filesystem" "singlefile" ];
|
type = types.enum [
|
||||||
|
"filesystem"
|
||||||
|
"singlefile"
|
||||||
|
];
|
||||||
default = "filesystem";
|
default = "filesystem";
|
||||||
description = "The type of the storage.";
|
description = "The type of the storage.";
|
||||||
};
|
};
|
||||||
|
|
@ -41,7 +44,11 @@ let
|
||||||
remoteModule = types.submodule {
|
remoteModule = types.submodule {
|
||||||
options = {
|
options = {
|
||||||
type = mkOption {
|
type = mkOption {
|
||||||
type = types.enum [ "caldav" "http" "google_calendar" ];
|
type = types.enum [
|
||||||
|
"caldav"
|
||||||
|
"http"
|
||||||
|
"google_calendar"
|
||||||
|
];
|
||||||
description = "The type of the storage.";
|
description = "The type of the storage.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -60,7 +67,10 @@ let
|
||||||
passwordCommand = mkOption {
|
passwordCommand = mkOption {
|
||||||
type = types.nullOr (types.listOf types.str);
|
type = types.nullOr (types.listOf types.str);
|
||||||
default = null;
|
default = null;
|
||||||
example = [ "pass" "caldav" ];
|
example = [
|
||||||
|
"pass"
|
||||||
|
"caldav"
|
||||||
|
];
|
||||||
description = ''
|
description = ''
|
||||||
A command that prints the password to standard output.
|
A command that prints the password to standard output.
|
||||||
'';
|
'';
|
||||||
|
|
@ -68,62 +78,66 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
calendarOpts = { name, ... }: {
|
calendarOpts =
|
||||||
options = {
|
{ name, ... }:
|
||||||
name = mkOption {
|
{
|
||||||
type = types.str;
|
options = {
|
||||||
readOnly = true;
|
name = mkOption {
|
||||||
description = ''
|
type = types.str;
|
||||||
Unique identifier of the calendar. This is set to the
|
readOnly = true;
|
||||||
attribute name of the calendar configuration.
|
description = ''
|
||||||
'';
|
Unique identifier of the calendar. This is set to the
|
||||||
|
attribute name of the calendar configuration.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
primary = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Whether this is the primary account. Only one account may be
|
||||||
|
set as primary.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
primaryCollection = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
The primary collection of the account. Required when an
|
||||||
|
account has multiple collections.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
local = mkOption {
|
||||||
|
type = localModule name;
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Local configuration for the calendar.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
remote = mkOption {
|
||||||
|
type = types.nullOr remoteModule;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Remote configuration for the calendar.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
primary = mkOption {
|
config = {
|
||||||
type = types.bool;
|
name = name;
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
Whether this is the primary account. Only one account may be
|
|
||||||
set as primary.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
primaryCollection = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
The primary collection of the account. Required when an
|
|
||||||
account has multiple collections.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
local = mkOption {
|
|
||||||
type = localModule name;
|
|
||||||
default = { };
|
|
||||||
description = ''
|
|
||||||
Local configuration for the calendar.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
remote = mkOption {
|
|
||||||
type = types.nullOr remoteModule;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Remote configuration for the calendar.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = { name = name; };
|
in
|
||||||
};
|
{
|
||||||
|
|
||||||
in {
|
|
||||||
options.accounts.calendar = {
|
options.accounts.calendar = {
|
||||||
basePath = mkOption {
|
basePath = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
example = ".calendar";
|
example = ".calendar";
|
||||||
apply = p:
|
apply = p: if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
|
||||||
if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
|
|
||||||
description = ''
|
description = ''
|
||||||
The base directory in which to save calendars. May be a
|
The base directory in which to save calendars. May be a
|
||||||
relative path, in which case it is relative the home
|
relative path, in which case it is relative the home
|
||||||
|
|
@ -132,25 +146,32 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
accounts = mkOption {
|
accounts = mkOption {
|
||||||
type = types.attrsOf (types.submodule [
|
type = types.attrsOf (
|
||||||
calendarOpts
|
types.submodule [
|
||||||
(import ../programs/vdirsyncer-accounts.nix)
|
calendarOpts
|
||||||
(import ../programs/khal-accounts.nix)
|
(import ../programs/vdirsyncer-accounts.nix)
|
||||||
(import ../programs/khal-calendar-accounts.nix)
|
(import ../programs/khal-accounts.nix)
|
||||||
]);
|
(import ../programs/khal-calendar-accounts.nix)
|
||||||
|
]
|
||||||
|
);
|
||||||
default = { };
|
default = { };
|
||||||
description = "List of calendars.";
|
description = "List of calendars.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = lib.mkIf (cfg.accounts != { }) {
|
config = lib.mkIf (cfg.accounts != { }) {
|
||||||
assertions = let
|
assertions =
|
||||||
primaries = lib.catAttrs "name"
|
let
|
||||||
(lib.filter (a: a.primary) (lib.attrValues cfg.accounts));
|
primaries = lib.catAttrs "name" (lib.filter (a: a.primary) (lib.attrValues cfg.accounts));
|
||||||
in [{
|
in
|
||||||
assertion = lib.length primaries <= 1;
|
[
|
||||||
message = "Must have at most one primary calendar account but found "
|
{
|
||||||
+ toString (lib.length primaries) + ", namely "
|
assertion = lib.length primaries <= 1;
|
||||||
+ lib.concatStringsSep ", " primaries;
|
message =
|
||||||
}];
|
"Must have at most one primary calendar account but found "
|
||||||
|
+ toString (lib.length primaries)
|
||||||
|
+ ", namely "
|
||||||
|
+ lib.concatStringsSep ", " primaries;
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,19 +5,22 @@ let
|
||||||
|
|
||||||
cfg = config.accounts.contact;
|
cfg = config.accounts.contact;
|
||||||
|
|
||||||
localModule = name:
|
localModule =
|
||||||
|
name:
|
||||||
types.submodule {
|
types.submodule {
|
||||||
options = {
|
options = {
|
||||||
path = mkOption {
|
path = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "${cfg.basePath}/${name}";
|
default = "${cfg.basePath}/${name}";
|
||||||
defaultText =
|
defaultText = lib.literalExpression "‹accounts.contact.basePath›/‹name›";
|
||||||
lib.literalExpression "‹accounts.contact.basePath›/‹name›";
|
|
||||||
description = "The path of the storage.";
|
description = "The path of the storage.";
|
||||||
};
|
};
|
||||||
|
|
||||||
type = mkOption {
|
type = mkOption {
|
||||||
type = types.enum [ "filesystem" "singlefile" ];
|
type = types.enum [
|
||||||
|
"filesystem"
|
||||||
|
"singlefile"
|
||||||
|
];
|
||||||
description = "The type of the storage.";
|
description = "The type of the storage.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -41,7 +44,11 @@ let
|
||||||
remoteModule = types.submodule {
|
remoteModule = types.submodule {
|
||||||
options = {
|
options = {
|
||||||
type = mkOption {
|
type = mkOption {
|
||||||
type = types.enum [ "carddav" "http" "google_contacts" ];
|
type = types.enum [
|
||||||
|
"carddav"
|
||||||
|
"http"
|
||||||
|
"google_contacts"
|
||||||
|
];
|
||||||
description = "The type of the storage.";
|
description = "The type of the storage.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -69,7 +76,10 @@ let
|
||||||
passwordCommand = mkOption {
|
passwordCommand = mkOption {
|
||||||
type = types.nullOr (types.listOf types.str);
|
type = types.nullOr (types.listOf types.str);
|
||||||
default = null;
|
default = null;
|
||||||
example = [ "pass" "caldav" ];
|
example = [
|
||||||
|
"pass"
|
||||||
|
"caldav"
|
||||||
|
];
|
||||||
description = ''
|
description = ''
|
||||||
A command that prints the password to standard output.
|
A command that prints the password to standard output.
|
||||||
'';
|
'';
|
||||||
|
|
@ -77,43 +87,47 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
contactOpts = { name, ... }: {
|
contactOpts =
|
||||||
options = {
|
{ name, ... }:
|
||||||
name = mkOption {
|
{
|
||||||
type = types.str;
|
options = {
|
||||||
readOnly = true;
|
name = mkOption {
|
||||||
description = ''
|
type = types.str;
|
||||||
Unique identifier of the contact account. This is set to the
|
readOnly = true;
|
||||||
attribute name of the contact configuration.
|
description = ''
|
||||||
'';
|
Unique identifier of the contact account. This is set to the
|
||||||
|
attribute name of the contact configuration.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
local = mkOption {
|
||||||
|
type = types.nullOr (localModule name);
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Local configuration for the contacts.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
remote = mkOption {
|
||||||
|
type = types.nullOr remoteModule;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Remote configuration for the contacts.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
local = mkOption {
|
config = {
|
||||||
type = types.nullOr (localModule name);
|
name = name;
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Local configuration for the contacts.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
remote = mkOption {
|
|
||||||
type = types.nullOr remoteModule;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Remote configuration for the contacts.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = { name = name; };
|
in
|
||||||
};
|
{
|
||||||
|
|
||||||
in {
|
|
||||||
options.accounts.contact = {
|
options.accounts.contact = {
|
||||||
basePath = mkOption {
|
basePath = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
apply = p:
|
apply = p: if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
|
||||||
if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
|
|
||||||
description = ''
|
description = ''
|
||||||
The base directory in which to save contacts. May be a
|
The base directory in which to save contacts. May be a
|
||||||
relative path, in which case it is relative the home
|
relative path, in which case it is relative the home
|
||||||
|
|
@ -122,12 +136,14 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
accounts = mkOption {
|
accounts = mkOption {
|
||||||
type = types.attrsOf (types.submodule [
|
type = types.attrsOf (
|
||||||
contactOpts
|
types.submodule [
|
||||||
(import ../programs/vdirsyncer-accounts.nix)
|
contactOpts
|
||||||
(import ../programs/khal-accounts.nix)
|
(import ../programs/vdirsyncer-accounts.nix)
|
||||||
(import ../programs/khal-contact-accounts.nix)
|
(import ../programs/khal-accounts.nix)
|
||||||
]);
|
(import ../programs/khal-contact-accounts.nix)
|
||||||
|
]
|
||||||
|
);
|
||||||
default = { };
|
default = { };
|
||||||
description = "List of contacts.";
|
description = "List of contacts.";
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) mkDefault mkIf mkOption types;
|
inherit (lib)
|
||||||
|
mkDefault
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.accounts.email;
|
cfg = config.accounts.email;
|
||||||
|
|
||||||
|
|
@ -66,7 +71,11 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
showSignature = mkOption {
|
showSignature = mkOption {
|
||||||
type = types.enum [ "append" "attach" "none" ];
|
type = types.enum [
|
||||||
|
"append"
|
||||||
|
"attach"
|
||||||
|
"none"
|
||||||
|
];
|
||||||
default = "none";
|
default = "none";
|
||||||
description = "Method to communicate the signature.";
|
description = "Method to communicate the signature.";
|
||||||
};
|
};
|
||||||
|
|
@ -195,320 +204,333 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
maildirModule = types.submodule ({ config, ... }: {
|
maildirModule = types.submodule (
|
||||||
options = {
|
{ config, ... }:
|
||||||
path = mkOption {
|
{
|
||||||
type = types.str;
|
options = {
|
||||||
description = ''
|
path = mkOption {
|
||||||
Path to maildir directory where mail for this account is
|
type = types.str;
|
||||||
stored. This is relative to the base maildir path.
|
description = ''
|
||||||
'';
|
Path to maildir directory where mail for this account is
|
||||||
|
stored. This is relative to the base maildir path.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
absPath = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
readOnly = true;
|
||||||
|
internal = true;
|
||||||
|
default = "${cfg.maildirBasePath}/${config.path}";
|
||||||
|
description = ''
|
||||||
|
A convenience option whose value is the absolute path of
|
||||||
|
this maildir.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
absPath = mkOption {
|
mailAccountOpts =
|
||||||
type = types.path;
|
{ name, config, ... }:
|
||||||
readOnly = true;
|
{
|
||||||
internal = true;
|
options = {
|
||||||
default = "${cfg.maildirBasePath}/${config.path}";
|
name = mkOption {
|
||||||
description = ''
|
type = types.str;
|
||||||
A convenience option whose value is the absolute path of
|
readOnly = true;
|
||||||
this maildir.
|
description = ''
|
||||||
'';
|
Unique identifier of the account. This is set to the
|
||||||
};
|
attribute name of the account configuration.
|
||||||
};
|
'';
|
||||||
});
|
};
|
||||||
|
|
||||||
mailAccountOpts = { name, config, ... }: {
|
primary = mkOption {
|
||||||
options = {
|
type = types.bool;
|
||||||
name = mkOption {
|
default = false;
|
||||||
type = types.str;
|
description = ''
|
||||||
readOnly = true;
|
Whether this is the primary account. Only one account may be
|
||||||
description = ''
|
set as primary.
|
||||||
Unique identifier of the account. This is set to the
|
'';
|
||||||
attribute name of the account configuration.
|
};
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
primary = mkOption {
|
flavor = mkOption {
|
||||||
type = types.bool;
|
type = types.enum [
|
||||||
default = false;
|
"plain"
|
||||||
description = ''
|
"gmail.com"
|
||||||
Whether this is the primary account. Only one account may be
|
"runbox.com"
|
||||||
set as primary.
|
"fastmail.com"
|
||||||
'';
|
"yandex.com"
|
||||||
};
|
"outlook.office365.com"
|
||||||
|
"migadu.com"
|
||||||
|
];
|
||||||
|
default = "plain";
|
||||||
|
description = ''
|
||||||
|
Some email providers have peculiar behavior that require
|
||||||
|
special treatment. This option is therefore intended to
|
||||||
|
indicate the nature of the provider.
|
||||||
|
|
||||||
flavor = mkOption {
|
When this indicates a specific provider then, for example,
|
||||||
type = types.enum [
|
the IMAP, SMTP, and JMAP server configuration may be set
|
||||||
"plain"
|
automatically.
|
||||||
"gmail.com"
|
'';
|
||||||
"runbox.com"
|
};
|
||||||
"fastmail.com"
|
|
||||||
"yandex.com"
|
|
||||||
"outlook.office365.com"
|
|
||||||
"migadu.com"
|
|
||||||
];
|
|
||||||
default = "plain";
|
|
||||||
description = ''
|
|
||||||
Some email providers have peculiar behavior that require
|
|
||||||
special treatment. This option is therefore intended to
|
|
||||||
indicate the nature of the provider.
|
|
||||||
|
|
||||||
When this indicates a specific provider then, for example,
|
address = mkOption {
|
||||||
the IMAP, SMTP, and JMAP server configuration may be set
|
type = types.strMatching ".*@.*";
|
||||||
automatically.
|
example = "jane.doe@example.org";
|
||||||
'';
|
description = "The email address of this account.";
|
||||||
};
|
};
|
||||||
|
|
||||||
address = mkOption {
|
aliases = mkOption {
|
||||||
type = types.strMatching ".*@.*";
|
description = "Alternative identities of this account.";
|
||||||
example = "jane.doe@example.org";
|
default = [ ];
|
||||||
description = "The email address of this account.";
|
example = [
|
||||||
};
|
"webmaster@example.org"
|
||||||
|
"admin@example.org"
|
||||||
|
];
|
||||||
|
type = types.listOf (
|
||||||
|
types.oneOf [
|
||||||
|
(types.strMatching ".*@.*")
|
||||||
|
(types.submodule {
|
||||||
|
options = {
|
||||||
|
realName = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "Jane Doe";
|
||||||
|
description = "Name displayed when sending mails.";
|
||||||
|
};
|
||||||
|
address = mkOption {
|
||||||
|
type = types.strMatching ".*@.*";
|
||||||
|
example = "jane.doe@example.org";
|
||||||
|
description = "The email address of this identity.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
aliases = mkOption {
|
realName = mkOption {
|
||||||
description = "Alternative identities of this account.";
|
type = types.str;
|
||||||
default = [ ];
|
example = "Jane Doe";
|
||||||
example = [ "webmaster@example.org" "admin@example.org" ];
|
description = "Name displayed when sending mails.";
|
||||||
type = types.listOf (types.oneOf [
|
};
|
||||||
(types.strMatching ".*@.*")
|
|
||||||
(types.submodule {
|
userName = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
The server username of this account. This will be used as
|
||||||
|
the SMTP, IMAP, and JMAP user name.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
passwordCommand = mkOption {
|
||||||
|
type = types.nullOr (types.either types.str (types.listOf types.str));
|
||||||
|
default = null;
|
||||||
|
apply = p: if lib.isString p then lib.splitString " " p else p;
|
||||||
|
example = "secret-tool lookup email me@example.org";
|
||||||
|
description = ''
|
||||||
|
A command, which when run writes the account password on
|
||||||
|
standard output.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
folders = mkOption {
|
||||||
|
type = types.submodule {
|
||||||
options = {
|
options = {
|
||||||
realName = mkOption {
|
inbox = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
example = "Jane Doe";
|
default = "Inbox";
|
||||||
description = "Name displayed when sending mails.";
|
description = ''
|
||||||
|
Relative path of the inbox mail.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
address = mkOption {
|
|
||||||
type = types.strMatching ".*@.*";
|
sent = mkOption {
|
||||||
example = "jane.doe@example.org";
|
type = types.nullOr types.str;
|
||||||
description = "The email address of this identity.";
|
default = "Sent";
|
||||||
|
description = ''
|
||||||
|
Relative path of the sent mail folder.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
realName = mkOption {
|
drafts = mkOption {
|
||||||
type = types.str;
|
type = types.nullOr types.str;
|
||||||
example = "Jane Doe";
|
default = "Drafts";
|
||||||
description = "Name displayed when sending mails.";
|
description = ''
|
||||||
};
|
Relative path of the drafts mail folder.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
userName = mkOption {
|
trash = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.str;
|
||||||
default = null;
|
default = "Trash";
|
||||||
description = ''
|
description = ''
|
||||||
The server username of this account. This will be used as
|
Relative path of the deleted mail folder.
|
||||||
the SMTP, IMAP, and JMAP user name.
|
'';
|
||||||
'';
|
};
|
||||||
};
|
|
||||||
|
|
||||||
passwordCommand = mkOption {
|
|
||||||
type = types.nullOr (types.either types.str (types.listOf types.str));
|
|
||||||
default = null;
|
|
||||||
apply = p: if lib.isString p then lib.splitString " " p else p;
|
|
||||||
example = "secret-tool lookup email me@example.org";
|
|
||||||
description = ''
|
|
||||||
A command, which when run writes the account password on
|
|
||||||
standard output.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
folders = mkOption {
|
|
||||||
type = types.submodule {
|
|
||||||
options = {
|
|
||||||
inbox = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "Inbox";
|
|
||||||
description = ''
|
|
||||||
Relative path of the inbox mail.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
sent = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = "Sent";
|
|
||||||
description = ''
|
|
||||||
Relative path of the sent mail folder.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
drafts = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = "Drafts";
|
|
||||||
description = ''
|
|
||||||
Relative path of the drafts mail folder.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
trash = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "Trash";
|
|
||||||
description = ''
|
|
||||||
Relative path of the deleted mail folder.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Standard email folders.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
imap = mkOption {
|
||||||
|
type = types.nullOr imapModule;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
The IMAP configuration to use for this account.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
jmap = mkOption {
|
||||||
|
type = types.nullOr jmapModule;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
The JMAP configuration to use for this account.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
signature = mkOption {
|
||||||
|
type = signatureModule;
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Signature configuration.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
gpg = mkOption {
|
||||||
|
type = types.nullOr gpgModule;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
GPG configuration.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
smtp = mkOption {
|
||||||
|
type = types.nullOr smtpModule;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
The SMTP configuration to use for this account.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
maildir = mkOption {
|
||||||
|
type = types.nullOr maildirModule;
|
||||||
|
defaultText = {
|
||||||
|
path = "\${name}";
|
||||||
|
};
|
||||||
|
description = ''
|
||||||
|
Maildir configuration for this account.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
default = { };
|
|
||||||
description = ''
|
|
||||||
Standard email folders.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
imap = mkOption {
|
config = lib.mkMerge [
|
||||||
type = types.nullOr imapModule;
|
{
|
||||||
default = null;
|
name = name;
|
||||||
description = ''
|
maildir = lib.mkOptionDefault { path = "${name}"; };
|
||||||
The IMAP configuration to use for this account.
|
}
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
jmap = mkOption {
|
(mkIf (config.flavor == "yandex.com") {
|
||||||
type = types.nullOr jmapModule;
|
userName = mkDefault config.address;
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
The JMAP configuration to use for this account.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
signature = mkOption {
|
imap = {
|
||||||
type = signatureModule;
|
host = "imap.yandex.com";
|
||||||
default = { };
|
port = 993;
|
||||||
description = ''
|
tls.enable = true;
|
||||||
Signature configuration.
|
};
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
gpg = mkOption {
|
smtp = {
|
||||||
type = types.nullOr gpgModule;
|
host = "smtp.yandex.com";
|
||||||
default = null;
|
port = 465;
|
||||||
description = ''
|
tls.enable = true;
|
||||||
GPG configuration.
|
};
|
||||||
'';
|
})
|
||||||
};
|
|
||||||
|
|
||||||
smtp = mkOption {
|
(mkIf (config.flavor == "outlook.office365.com") {
|
||||||
type = types.nullOr smtpModule;
|
userName = mkDefault config.address;
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
The SMTP configuration to use for this account.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
maildir = mkOption {
|
imap = {
|
||||||
type = types.nullOr maildirModule;
|
host = "outlook.office365.com";
|
||||||
defaultText = { path = "\${name}"; };
|
port = 993;
|
||||||
description = ''
|
tls.enable = true;
|
||||||
Maildir configuration for this account.
|
};
|
||||||
'';
|
|
||||||
};
|
smtp = {
|
||||||
|
host = "smtp.office365.com";
|
||||||
|
port = 587;
|
||||||
|
tls = {
|
||||||
|
enable = true;
|
||||||
|
useStartTls = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(mkIf (config.flavor == "fastmail.com") {
|
||||||
|
userName = mkDefault config.address;
|
||||||
|
|
||||||
|
imap = {
|
||||||
|
host = "imap.fastmail.com";
|
||||||
|
port = 993;
|
||||||
|
};
|
||||||
|
|
||||||
|
smtp = {
|
||||||
|
host = "smtp.fastmail.com";
|
||||||
|
port = if config.smtp.tls.useStartTls then 587 else 465;
|
||||||
|
};
|
||||||
|
|
||||||
|
jmap = {
|
||||||
|
host = "fastmail.com";
|
||||||
|
sessionUrl = "https://jmap.fastmail.com/.well-known/jmap";
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(mkIf (config.flavor == "migadu.com") {
|
||||||
|
userName = mkDefault config.address;
|
||||||
|
|
||||||
|
imap = {
|
||||||
|
host = "imap.migadu.com";
|
||||||
|
port = 993;
|
||||||
|
};
|
||||||
|
|
||||||
|
smtp = {
|
||||||
|
host = "smtp.migadu.com";
|
||||||
|
port = 465;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(mkIf (config.flavor == "gmail.com") {
|
||||||
|
userName = mkDefault config.address;
|
||||||
|
|
||||||
|
imap = {
|
||||||
|
host = "imap.gmail.com";
|
||||||
|
port = 993;
|
||||||
|
};
|
||||||
|
|
||||||
|
smtp = {
|
||||||
|
host = "smtp.gmail.com";
|
||||||
|
port = if config.smtp.tls.useStartTls then 587 else 465;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(mkIf (config.flavor == "runbox.com") {
|
||||||
|
imap = {
|
||||||
|
host = "mail.runbox.com";
|
||||||
|
port = 993;
|
||||||
|
};
|
||||||
|
|
||||||
|
smtp = {
|
||||||
|
host = "mail.runbox.com";
|
||||||
|
port = if config.smtp.tls.useStartTls then 587 else 465;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkMerge [
|
in
|
||||||
{
|
{
|
||||||
name = name;
|
|
||||||
maildir = lib.mkOptionDefault { path = "${name}"; };
|
|
||||||
}
|
|
||||||
|
|
||||||
(mkIf (config.flavor == "yandex.com") {
|
|
||||||
userName = mkDefault config.address;
|
|
||||||
|
|
||||||
imap = {
|
|
||||||
host = "imap.yandex.com";
|
|
||||||
port = 993;
|
|
||||||
tls.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
smtp = {
|
|
||||||
host = "smtp.yandex.com";
|
|
||||||
port = 465;
|
|
||||||
tls.enable = true;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
|
|
||||||
(mkIf (config.flavor == "outlook.office365.com") {
|
|
||||||
userName = mkDefault config.address;
|
|
||||||
|
|
||||||
imap = {
|
|
||||||
host = "outlook.office365.com";
|
|
||||||
port = 993;
|
|
||||||
tls.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
smtp = {
|
|
||||||
host = "smtp.office365.com";
|
|
||||||
port = 587;
|
|
||||||
tls = {
|
|
||||||
enable = true;
|
|
||||||
useStartTls = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
|
|
||||||
(mkIf (config.flavor == "fastmail.com") {
|
|
||||||
userName = mkDefault config.address;
|
|
||||||
|
|
||||||
imap = {
|
|
||||||
host = "imap.fastmail.com";
|
|
||||||
port = 993;
|
|
||||||
};
|
|
||||||
|
|
||||||
smtp = {
|
|
||||||
host = "smtp.fastmail.com";
|
|
||||||
port = if config.smtp.tls.useStartTls then 587 else 465;
|
|
||||||
};
|
|
||||||
|
|
||||||
jmap = {
|
|
||||||
host = "fastmail.com";
|
|
||||||
sessionUrl = "https://jmap.fastmail.com/.well-known/jmap";
|
|
||||||
};
|
|
||||||
})
|
|
||||||
|
|
||||||
(mkIf (config.flavor == "migadu.com") {
|
|
||||||
userName = mkDefault config.address;
|
|
||||||
|
|
||||||
imap = {
|
|
||||||
host = "imap.migadu.com";
|
|
||||||
port = 993;
|
|
||||||
};
|
|
||||||
|
|
||||||
smtp = {
|
|
||||||
host = "smtp.migadu.com";
|
|
||||||
port = 465;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
|
|
||||||
(mkIf (config.flavor == "gmail.com") {
|
|
||||||
userName = mkDefault config.address;
|
|
||||||
|
|
||||||
imap = {
|
|
||||||
host = "imap.gmail.com";
|
|
||||||
port = 993;
|
|
||||||
};
|
|
||||||
|
|
||||||
smtp = {
|
|
||||||
host = "smtp.gmail.com";
|
|
||||||
port = if config.smtp.tls.useStartTls then 587 else 465;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
|
|
||||||
(mkIf (config.flavor == "runbox.com") {
|
|
||||||
imap = {
|
|
||||||
host = "mail.runbox.com";
|
|
||||||
port = 993;
|
|
||||||
};
|
|
||||||
|
|
||||||
smtp = {
|
|
||||||
host = "mail.runbox.com";
|
|
||||||
port = if config.smtp.tls.useStartTls then 587 else 465;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
in {
|
|
||||||
options.accounts.email = {
|
options.accounts.email = {
|
||||||
certificatesFile = mkOption {
|
certificatesFile = mkOption {
|
||||||
type = types.nullOr types.path;
|
type = types.nullOr types.path;
|
||||||
|
|
@ -524,8 +546,7 @@ in {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "${config.home.homeDirectory}/Maildir";
|
default = "${config.home.homeDirectory}/Maildir";
|
||||||
defaultText = "Maildir";
|
defaultText = "Maildir";
|
||||||
apply = p:
|
apply = p: if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
|
||||||
if lib.hasPrefix "/" p then p else "${config.home.homeDirectory}/${p}";
|
|
||||||
description = ''
|
description = ''
|
||||||
The base directory for account maildir directories. May be a
|
The base directory for account maildir directories. May be a
|
||||||
relative path (e.g. the user setting this value as "MyMaildir"),
|
relative path (e.g. the user setting this value as "MyMaildir"),
|
||||||
|
|
@ -543,16 +564,18 @@ in {
|
||||||
|
|
||||||
config = mkIf (cfg.accounts != { }) {
|
config = mkIf (cfg.accounts != { }) {
|
||||||
assertions = [
|
assertions = [
|
||||||
(let
|
(
|
||||||
primaries = lib.catAttrs "name"
|
let
|
||||||
(lib.filter (a: a.primary) (lib.attrValues cfg.accounts));
|
primaries = lib.catAttrs "name" (lib.filter (a: a.primary) (lib.attrValues cfg.accounts));
|
||||||
in {
|
in
|
||||||
assertion = lib.length primaries == 1;
|
{
|
||||||
message = "Must have exactly one primary mail account but found "
|
assertion = lib.length primaries == 1;
|
||||||
+ toString (lib.length primaries)
|
message =
|
||||||
+ lib.optionalString (lib.length primaries > 1)
|
"Must have exactly one primary mail account but found "
|
||||||
(", namely " + lib.concatStringsSep ", " primaries);
|
+ toString (lib.length primaries)
|
||||||
})
|
+ lib.optionalString (lib.length primaries > 1) (", namely " + lib.concatStringsSep ", " primaries);
|
||||||
|
}
|
||||||
|
)
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,27 @@
|
||||||
{ config, options, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
options,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
mkEnableOption mkOption mkIf mkMerge mkDefault mkAliasOptionModule types
|
mkEnableOption
|
||||||
literalExpression escapeShellArg hm getAttrFromPath any optional;
|
mkOption
|
||||||
|
mkIf
|
||||||
|
mkMerge
|
||||||
|
mkDefault
|
||||||
|
mkAliasOptionModule
|
||||||
|
types
|
||||||
|
literalExpression
|
||||||
|
escapeShellArg
|
||||||
|
hm
|
||||||
|
getAttrFromPath
|
||||||
|
any
|
||||||
|
optional
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.home.pointerCursor;
|
cfg = config.home.pointerCursor;
|
||||||
opts = options.home.pointerCursor;
|
opts = options.home.pointerCursor;
|
||||||
|
|
@ -51,11 +69,13 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
dotIcons = {
|
dotIcons = {
|
||||||
enable = mkEnableOption ''
|
enable =
|
||||||
`.icons` config generation for {option}`home.pointerCursor`
|
mkEnableOption ''
|
||||||
'' // {
|
`.icons` config generation for {option}`home.pointerCursor`
|
||||||
default = true;
|
''
|
||||||
};
|
// {
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
hyprcursor = {
|
hyprcursor = {
|
||||||
|
|
@ -70,15 +90,12 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
sway = {
|
sway = {
|
||||||
enable = mkEnableOption
|
enable = mkEnableOption "sway config generation for {option}`home.pointerCursor`";
|
||||||
"sway config generation for {option}`home.pointerCursor`";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
cursorPath = "${cfg.package}/share/icons/${escapeShellArg cfg.name}/cursors/${
|
cursorPath = "${cfg.package}/share/icons/${escapeShellArg cfg.name}/cursors/${escapeShellArg cfg.x11.defaultCursor}";
|
||||||
escapeShellArg cfg.x11.defaultCursor
|
|
||||||
}";
|
|
||||||
|
|
||||||
defaultIndexThemePackage = pkgs.writeTextFile {
|
defaultIndexThemePackage = pkgs.writeTextFile {
|
||||||
name = "index.theme";
|
name = "index.theme";
|
||||||
|
|
@ -94,31 +111,44 @@ let
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.league ];
|
meta.maintainers = [ lib.maintainers.league ];
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
(mkAliasOptionModule [ "xsession" "pointerCursor" "package" ] [
|
(mkAliasOptionModule
|
||||||
"home"
|
[ "xsession" "pointerCursor" "package" ]
|
||||||
"pointerCursor"
|
[
|
||||||
"package"
|
"home"
|
||||||
])
|
"pointerCursor"
|
||||||
(mkAliasOptionModule [ "xsession" "pointerCursor" "name" ] [
|
"package"
|
||||||
"home"
|
]
|
||||||
"pointerCursor"
|
)
|
||||||
"name"
|
(mkAliasOptionModule
|
||||||
])
|
[ "xsession" "pointerCursor" "name" ]
|
||||||
(mkAliasOptionModule [ "xsession" "pointerCursor" "size" ] [
|
[
|
||||||
"home"
|
"home"
|
||||||
"pointerCursor"
|
"pointerCursor"
|
||||||
"size"
|
"name"
|
||||||
])
|
]
|
||||||
(mkAliasOptionModule [ "xsession" "pointerCursor" "defaultCursor" ] [
|
)
|
||||||
"home"
|
(mkAliasOptionModule
|
||||||
"pointerCursor"
|
[ "xsession" "pointerCursor" "size" ]
|
||||||
"x11"
|
[
|
||||||
"defaultCursor"
|
"home"
|
||||||
])
|
"pointerCursor"
|
||||||
|
"size"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
(mkAliasOptionModule
|
||||||
|
[ "xsession" "pointerCursor" "defaultCursor" ]
|
||||||
|
[
|
||||||
|
"home"
|
||||||
|
"pointerCursor"
|
||||||
|
"x11"
|
||||||
|
"defaultCursor"
|
||||||
|
]
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -145,107 +175,121 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let
|
config =
|
||||||
# Check if enable option was explicitly defined by the user
|
let
|
||||||
enableDefined = any (x: x ? enable) opts.definitions;
|
# Check if enable option was explicitly defined by the user
|
||||||
|
enableDefined = any (x: x ? enable) opts.definitions;
|
||||||
|
|
||||||
# Determine if cursor configuration should be enabled
|
# Determine if cursor configuration should be enabled
|
||||||
enable = if enableDefined then cfg.enable else cfg != null;
|
enable = if enableDefined then cfg.enable else cfg != null;
|
||||||
in mkMerge [
|
in
|
||||||
(mkIf enable (mkMerge [
|
mkMerge [
|
||||||
{
|
(mkIf enable (mkMerge [
|
||||||
assertions = [
|
{
|
||||||
(hm.assertions.assertPlatform "home.pointerCursor" pkgs
|
assertions = [
|
||||||
lib.platforms.linux)
|
(hm.assertions.assertPlatform "home.pointerCursor" pkgs lib.platforms.linux)
|
||||||
];
|
];
|
||||||
|
|
||||||
home.packages = [ cfg.package defaultIndexThemePackage ];
|
home.packages = [
|
||||||
|
cfg.package
|
||||||
|
defaultIndexThemePackage
|
||||||
|
];
|
||||||
|
|
||||||
home.sessionVariables = {
|
home.sessionVariables = {
|
||||||
XCURSOR_SIZE = mkDefault cfg.size;
|
XCURSOR_SIZE = mkDefault cfg.size;
|
||||||
XCURSOR_THEME = mkDefault cfg.name;
|
XCURSOR_THEME = mkDefault cfg.name;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Set directory to look for cursors in, needed for some applications
|
# Set directory to look for cursors in, needed for some applications
|
||||||
# that are unable to find cursors otherwise. See:
|
# that are unable to find cursors otherwise. See:
|
||||||
# https://github.com/nix-community/home-manager/issues/2812
|
# https://github.com/nix-community/home-manager/issues/2812
|
||||||
# https://wiki.archlinux.org/title/Cursor_themes#Environment_variable
|
# https://wiki.archlinux.org/title/Cursor_themes#Environment_variable
|
||||||
home.sessionSearchVariables.XCURSOR_PATH =
|
home.sessionSearchVariables.XCURSOR_PATH = [ "${config.home.profileDirectory}/share/icons" ];
|
||||||
[ "${config.home.profileDirectory}/share/icons" ];
|
|
||||||
|
|
||||||
# Add cursor icon link to $XDG_DATA_HOME/icons as well for redundancy.
|
# Add cursor icon link to $XDG_DATA_HOME/icons as well for redundancy.
|
||||||
xdg.dataFile."icons/default/index.theme".source =
|
xdg.dataFile."icons/default/index.theme".source =
|
||||||
"${defaultIndexThemePackage}/share/icons/default/index.theme";
|
"${defaultIndexThemePackage}/share/icons/default/index.theme";
|
||||||
xdg.dataFile."icons/${cfg.name}".source =
|
xdg.dataFile."icons/${cfg.name}".source = "${cfg.package}/share/icons/${cfg.name}";
|
||||||
"${cfg.package}/share/icons/${cfg.name}";
|
}
|
||||||
}
|
|
||||||
|
|
||||||
(mkIf cfg.dotIcons.enable {
|
(mkIf cfg.dotIcons.enable {
|
||||||
# Add symlink of cursor icon directory to $HOME/.icons, needed for
|
# Add symlink of cursor icon directory to $HOME/.icons, needed for
|
||||||
# backwards compatibility with some applications. See:
|
# backwards compatibility with some applications. See:
|
||||||
# https://specifications.freedesktop.org/icon-theme-spec/latest/ar01s03.html
|
# https://specifications.freedesktop.org/icon-theme-spec/latest/ar01s03.html
|
||||||
home.file.".icons/default/index.theme".source =
|
home.file.".icons/default/index.theme".source =
|
||||||
"${defaultIndexThemePackage}/share/icons/default/index.theme";
|
"${defaultIndexThemePackage}/share/icons/default/index.theme";
|
||||||
home.file.".icons/${cfg.name}".source =
|
home.file.".icons/${cfg.name}".source = "${cfg.package}/share/icons/${cfg.name}";
|
||||||
"${cfg.package}/share/icons/${cfg.name}";
|
})
|
||||||
})
|
|
||||||
|
|
||||||
(mkIf cfg.x11.enable {
|
(mkIf cfg.x11.enable {
|
||||||
xsession.profileExtra = ''
|
xsession.profileExtra = ''
|
||||||
${pkgs.xorg.xsetroot}/bin/xsetroot -xcf ${cursorPath} ${
|
${pkgs.xorg.xsetroot}/bin/xsetroot -xcf ${cursorPath} ${toString cfg.size}
|
||||||
toString cfg.size
|
'';
|
||||||
}
|
|
||||||
'';
|
|
||||||
|
|
||||||
xresources.properties = {
|
xresources.properties = {
|
||||||
"Xcursor.theme" = cfg.name;
|
"Xcursor.theme" = cfg.name;
|
||||||
"Xcursor.size" = cfg.size;
|
"Xcursor.size" = cfg.size;
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
(mkIf cfg.gtk.enable {
|
(mkIf cfg.gtk.enable {
|
||||||
gtk.cursorTheme = mkDefault { inherit (cfg) package name size; };
|
gtk.cursorTheme = mkDefault { inherit (cfg) package name size; };
|
||||||
})
|
})
|
||||||
|
|
||||||
(mkIf cfg.hyprcursor.enable {
|
(mkIf cfg.hyprcursor.enable {
|
||||||
home.sessionVariables = {
|
home.sessionVariables = {
|
||||||
HYPRCURSOR_THEME = cfg.name;
|
HYPRCURSOR_THEME = cfg.name;
|
||||||
HYPRCURSOR_SIZE = if cfg.hyprcursor.size != null then
|
HYPRCURSOR_SIZE = if cfg.hyprcursor.size != null then cfg.hyprcursor.size else cfg.size;
|
||||||
cfg.hyprcursor.size
|
};
|
||||||
else
|
})
|
||||||
cfg.size;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
|
|
||||||
(mkIf cfg.sway.enable {
|
(mkIf cfg.sway.enable {
|
||||||
wayland.windowManager.sway = {
|
wayland.windowManager.sway = {
|
||||||
config = {
|
config = {
|
||||||
seat = {
|
seat = {
|
||||||
"*" = {
|
"*" = {
|
||||||
xcursor_theme =
|
xcursor_theme = "${cfg.name} ${toString config.gtk.cursorTheme.size}";
|
||||||
"${cfg.name} ${toString config.gtk.cursorTheme.size}";
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
})
|
||||||
})
|
]))
|
||||||
]))
|
|
||||||
|
|
||||||
{
|
{
|
||||||
warnings = (optional (any (x:
|
warnings =
|
||||||
getAttrFromPath
|
(optional
|
||||||
([ "xsession" "pointerCursor" ] ++ [ x ] ++ [ "isDefined" ])
|
(any
|
||||||
options) [ "package" "name" "size" "defaultCursor" ]) ''
|
(
|
||||||
The option `xsession.pointerCursor` has been merged into `home.pointerCursor` and will be removed
|
x:
|
||||||
in the future. Please change to set `home.pointerCursor` directly and enable `home.pointerCursor.x11.enable`
|
getAttrFromPath (
|
||||||
to generate x11 specific cursor configurations. You can refer to the documentation for more details.
|
[
|
||||||
'') ++ (optional (opts.highestPrio != (lib.mkOptionDefault { }).priority
|
"xsession"
|
||||||
&& cfg == null) ''
|
"pointerCursor"
|
||||||
|
]
|
||||||
|
++ [ x ]
|
||||||
|
++ [ "isDefined" ]
|
||||||
|
) options
|
||||||
|
)
|
||||||
|
[
|
||||||
|
"package"
|
||||||
|
"name"
|
||||||
|
"size"
|
||||||
|
"defaultCursor"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
''
|
||||||
|
The option `xsession.pointerCursor` has been merged into `home.pointerCursor` and will be removed
|
||||||
|
in the future. Please change to set `home.pointerCursor` directly and enable `home.pointerCursor.x11.enable`
|
||||||
|
to generate x11 specific cursor configurations. You can refer to the documentation for more details.
|
||||||
|
''
|
||||||
|
)
|
||||||
|
++ (optional (opts.highestPrio != (lib.mkOptionDefault { }).priority && cfg == null) ''
|
||||||
Setting home.pointerCursor to null is deprecated.
|
Setting home.pointerCursor to null is deprecated.
|
||||||
Please update your configuration to explicitly set:
|
Please update your configuration to explicitly set:
|
||||||
|
|
||||||
home.pointerCursor.enable = false;
|
home.pointerCursor.enable = false;
|
||||||
'');
|
'');
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,12 @@
|
||||||
# below for changes:
|
# below for changes:
|
||||||
# https://github.com/NixOS/nixpkgs/blob/nixpkgs-unstable/pkgs/development/libraries/glibc/nix-locale-archive.patch
|
# https://github.com/NixOS/nixpkgs/blob/nixpkgs-unstable/pkgs/development/libraries/glibc/nix-locale-archive.patch
|
||||||
|
|
||||||
{ lib, pkgs, config, ... }:
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (config.i18n) glibcLocales;
|
inherit (config.i18n) glibcLocales;
|
||||||
|
|
@ -25,14 +30,20 @@ let
|
||||||
archivePath = "${glibcLocales}/lib/locale/locale-archive";
|
archivePath = "${glibcLocales}/lib/locale/locale-archive";
|
||||||
|
|
||||||
# lookup the version of glibcLocales and set the appropriate environment vars
|
# lookup the version of glibcLocales and set the appropriate environment vars
|
||||||
localeVars = if lib.versionAtLeast version "2.27" then {
|
localeVars =
|
||||||
LOCALE_ARCHIVE_2_27 = archivePath;
|
if lib.versionAtLeast version "2.27" then
|
||||||
} else if lib.versionAtLeast version "2.11" then {
|
{
|
||||||
LOCALE_ARCHIVE_2_11 = archivePath;
|
LOCALE_ARCHIVE_2_27 = archivePath;
|
||||||
} else
|
}
|
||||||
{ };
|
else if lib.versionAtLeast version "2.11" then
|
||||||
|
{
|
||||||
|
LOCALE_ARCHIVE_2_11 = archivePath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ };
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = with lib.maintainers; [ midchildan ];
|
meta.maintainers = with lib.maintainers; [ midchildan ];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,24 @@
|
||||||
{ configuration, pkgs, lib ? pkgs.lib
|
{
|
||||||
|
configuration,
|
||||||
|
pkgs,
|
||||||
|
lib ? pkgs.lib,
|
||||||
|
|
||||||
# Whether to check that each option has a matching declaration.
|
# Whether to check that each option has a matching declaration.
|
||||||
, check ? true
|
check ? true,
|
||||||
# Extra arguments passed to specialArgs.
|
# Extra arguments passed to specialArgs.
|
||||||
, extraSpecialArgs ? { } }:
|
extraSpecialArgs ? { },
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
collectFailed = cfg:
|
collectFailed = cfg: map (x: x.message) (lib.filter (x: !x.assertion) cfg.assertions);
|
||||||
map (x: x.message) (lib.filter (x: !x.assertion) cfg.assertions);
|
|
||||||
|
|
||||||
showWarnings = res:
|
showWarnings =
|
||||||
let f = w: x: builtins.trace "[1;31mwarning: ${w}[0m" x;
|
res:
|
||||||
in lib.fold f res res.config.warnings;
|
let
|
||||||
|
f = w: x: builtins.trace "[1;31mwarning: ${w}[0m" x;
|
||||||
|
in
|
||||||
|
lib.fold f res res.config.warnings;
|
||||||
|
|
||||||
extendedLib = import ./lib/stdlib-extended.nix lib;
|
extendedLib = import ./lib/stdlib-extended.nix lib;
|
||||||
|
|
||||||
|
|
@ -24,24 +30,33 @@ let
|
||||||
rawModule = extendedLib.evalModules {
|
rawModule = extendedLib.evalModules {
|
||||||
modules = [ configuration ] ++ hmModules;
|
modules = [ configuration ] ++ hmModules;
|
||||||
class = "homeManager";
|
class = "homeManager";
|
||||||
specialArgs = { modulesPath = builtins.toString ./.; } // extraSpecialArgs;
|
specialArgs = {
|
||||||
|
modulesPath = builtins.toString ./.;
|
||||||
|
} // extraSpecialArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
moduleChecks = raw:
|
moduleChecks =
|
||||||
showWarnings (let
|
raw:
|
||||||
failed = collectFailed raw.config;
|
showWarnings (
|
||||||
failedStr = lib.concatStringsSep "\n" (map (x: "- ${x}") failed);
|
let
|
||||||
in if failed == [ ] then
|
failed = collectFailed raw.config;
|
||||||
raw
|
failedStr = lib.concatStringsSep "\n" (map (x: "- ${x}") failed);
|
||||||
else
|
in
|
||||||
throw ''
|
if failed == [ ] then
|
||||||
|
raw
|
||||||
|
else
|
||||||
|
throw ''
|
||||||
|
|
||||||
Failed assertions:
|
Failed assertions:
|
||||||
${failedStr}'');
|
${failedStr}''
|
||||||
|
);
|
||||||
|
|
||||||
withExtraAttrs = rawModule:
|
withExtraAttrs =
|
||||||
let module = moduleChecks rawModule;
|
rawModule:
|
||||||
in {
|
let
|
||||||
|
module = moduleChecks rawModule;
|
||||||
|
in
|
||||||
|
{
|
||||||
inherit (module) options config;
|
inherit (module) options config;
|
||||||
|
|
||||||
activationPackage = module.config.home.activationPackage;
|
activationPackage = module.config.home.activationPackage;
|
||||||
|
|
@ -50,11 +65,13 @@ let
|
||||||
activation-script = module.config.home.activationPackage;
|
activation-script = module.config.home.activationPackage;
|
||||||
|
|
||||||
newsDisplay = rawModule.config.news.display;
|
newsDisplay = rawModule.config.news.display;
|
||||||
newsEntries = lib.sort (a: b: a.time > b.time)
|
newsEntries = lib.sort (a: b: a.time > b.time) (
|
||||||
(lib.filter (a: a.condition) rawModule.config.news.entries);
|
lib.filter (a: a.condition) rawModule.config.news.entries
|
||||||
|
);
|
||||||
|
|
||||||
inherit (module._module.args) pkgs;
|
inherit (module._module.args) pkgs;
|
||||||
|
|
||||||
extendModules = args: withExtraAttrs (rawModule.extendModules args);
|
extendModules = args: withExtraAttrs (rawModule.extendModules args);
|
||||||
};
|
};
|
||||||
in withExtraAttrs rawModule
|
in
|
||||||
|
withExtraAttrs rawModule
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ pkgs, config, lib, ... }:
|
{
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
|
|
@ -6,18 +11,24 @@ let
|
||||||
|
|
||||||
homeDirectory = config.home.homeDirectory;
|
homeDirectory = config.home.homeDirectory;
|
||||||
|
|
||||||
fileType = (import lib/file-type.nix {
|
fileType =
|
||||||
inherit homeDirectory lib pkgs;
|
(import lib/file-type.nix {
|
||||||
}).fileType;
|
inherit homeDirectory lib pkgs;
|
||||||
|
}).fileType;
|
||||||
|
|
||||||
sourceStorePath = file:
|
sourceStorePath =
|
||||||
|
file:
|
||||||
let
|
let
|
||||||
sourcePath = toString file.source;
|
sourcePath = toString file.source;
|
||||||
sourceName = config.lib.strings.storeFileName (baseNameOf sourcePath);
|
sourceName = config.lib.strings.storeFileName (baseNameOf sourcePath);
|
||||||
in
|
in
|
||||||
if builtins.hasContext sourcePath
|
if builtins.hasContext sourcePath then
|
||||||
then file.source
|
file.source
|
||||||
else builtins.path { path = file.source; name = sourceName; };
|
else
|
||||||
|
builtins.path {
|
||||||
|
path = file.source;
|
||||||
|
name = sourceName;
|
||||||
|
};
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
|
|
@ -25,7 +36,7 @@ in
|
||||||
options = {
|
options = {
|
||||||
home.file = lib.mkOption {
|
home.file = lib.mkOption {
|
||||||
description = "Attribute set of files to link into the user home.";
|
description = "Attribute set of files to link into the user home.";
|
||||||
default = {};
|
default = { };
|
||||||
type = fileType "home.file" "{env}`HOME`" homeDirectory;
|
type = fileType "home.file" "{env}`HOME`" homeDirectory;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -37,26 +48,29 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
assertions = [(
|
assertions = [
|
||||||
let
|
(
|
||||||
dups =
|
let
|
||||||
lib.attrNames
|
dups = lib.attrNames (
|
||||||
(lib.filterAttrs (n: v: v > 1)
|
lib.filterAttrs (n: v: v > 1) (
|
||||||
(lib.foldAttrs (acc: v: acc + v) 0
|
lib.foldAttrs (acc: v: acc + v) 0 (lib.mapAttrsToList (n: v: { ${v.target} = 1; }) cfg)
|
||||||
(lib.mapAttrsToList (n: v: { ${v.target} = 1; }) cfg)));
|
)
|
||||||
dupsStr = lib.concatStringsSep ", " dups;
|
);
|
||||||
in {
|
dupsStr = lib.concatStringsSep ", " dups;
|
||||||
assertion = dups == [];
|
in
|
||||||
message = ''
|
{
|
||||||
Conflicting managed target files: ${dupsStr}
|
assertion = dups == [ ];
|
||||||
|
message = ''
|
||||||
|
Conflicting managed target files: ${dupsStr}
|
||||||
|
|
||||||
This may happen, for example, if you have a configuration similar to
|
This may happen, for example, if you have a configuration similar to
|
||||||
|
|
||||||
home.file = {
|
home.file = {
|
||||||
conflict1 = { source = ./foo.nix; target = "baz"; };
|
conflict1 = { source = ./foo.nix; target = "baz"; };
|
||||||
conflict2 = { source = ./bar.nix; target = "baz"; };
|
conflict2 = { source = ./bar.nix; target = "baz"; };
|
||||||
}'';
|
}'';
|
||||||
})
|
}
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
# Using this function it is possible to make `home.file` create a
|
# Using this function it is possible to make `home.file` create a
|
||||||
|
|
@ -67,23 +81,23 @@ in
|
||||||
#
|
#
|
||||||
# would upon activation create a symlink `~/foo` that points to the
|
# would upon activation create a symlink `~/foo` that points to the
|
||||||
# absolute path of the `bar` file relative the configuration file.
|
# absolute path of the `bar` file relative the configuration file.
|
||||||
lib.file.mkOutOfStoreSymlink = path:
|
lib.file.mkOutOfStoreSymlink =
|
||||||
|
path:
|
||||||
let
|
let
|
||||||
pathStr = toString path;
|
pathStr = toString path;
|
||||||
name = lib.hm.strings.storeFileName (baseNameOf pathStr);
|
name = lib.hm.strings.storeFileName (baseNameOf pathStr);
|
||||||
in
|
in
|
||||||
pkgs.runCommandLocal name {} ''ln -s ${lib.escapeShellArg pathStr} $out'';
|
pkgs.runCommandLocal name { } ''ln -s ${lib.escapeShellArg pathStr} $out'';
|
||||||
|
|
||||||
# This verifies that the links we are about to create will not
|
# This verifies that the links we are about to create will not
|
||||||
# overwrite an existing file.
|
# overwrite an existing file.
|
||||||
home.activation.checkLinkTargets = lib.hm.dag.entryBefore ["writeBoundary"] (
|
home.activation.checkLinkTargets = lib.hm.dag.entryBefore [ "writeBoundary" ] (
|
||||||
let
|
let
|
||||||
# Paths that should be forcibly overwritten by Home Manager.
|
# Paths that should be forcibly overwritten by Home Manager.
|
||||||
# Caveat emptor!
|
# Caveat emptor!
|
||||||
forcedPaths =
|
forcedPaths = lib.concatMapStringsSep " " (p: ''"$HOME"/${lib.escapeShellArg p}'') (
|
||||||
lib.concatMapStringsSep " " (p: ''"$HOME"/${lib.escapeShellArg p}'')
|
lib.mapAttrsToList (n: v: v.target) (lib.filterAttrs (n: v: v.force) cfg)
|
||||||
(lib.mapAttrsToList (n: v: v.target)
|
);
|
||||||
(lib.filterAttrs (n: v: v.force) cfg));
|
|
||||||
|
|
||||||
storeDir = lib.escapeShellArg builtins.storeDir;
|
storeDir = lib.escapeShellArg builtins.storeDir;
|
||||||
|
|
||||||
|
|
@ -124,7 +138,7 @@ in
|
||||||
# and a failure during the intermediate state FA ∩ FB will not
|
# and a failure during the intermediate state FA ∩ FB will not
|
||||||
# result in lost links because this set of links are in both the
|
# result in lost links because this set of links are in both the
|
||||||
# source and target generation.
|
# source and target generation.
|
||||||
home.activation.linkGeneration = lib.hm.dag.entryAfter ["writeBoundary"] (
|
home.activation.linkGeneration = lib.hm.dag.entryAfter [ "writeBoundary" ] (
|
||||||
let
|
let
|
||||||
link = pkgs.writeShellScript "link" ''
|
link = pkgs.writeShellScript "link" ''
|
||||||
${config.lib.bash.initHomeManagerLib}
|
${config.lib.bash.initHomeManagerLib}
|
||||||
|
|
@ -189,43 +203,44 @@ in
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
''
|
''
|
||||||
function linkNewGen() {
|
function linkNewGen() {
|
||||||
_i "Creating home file links in %s" "$HOME"
|
_i "Creating home file links in %s" "$HOME"
|
||||||
|
|
||||||
local newGenFiles
|
local newGenFiles
|
||||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||||
find "$newGenFiles" \( -type f -or -type l \) \
|
find "$newGenFiles" \( -type f -or -type l \) \
|
||||||
-exec bash ${link} "$newGenFiles" {} +
|
-exec bash ${link} "$newGenFiles" {} +
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanOldGen() {
|
function cleanOldGen() {
|
||||||
if [[ ! -v oldGenPath || ! -e "$oldGenPath/home-files" ]] ; then
|
if [[ ! -v oldGenPath || ! -e "$oldGenPath/home-files" ]] ; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_i "Cleaning up orphan links from %s" "$HOME"
|
_i "Cleaning up orphan links from %s" "$HOME"
|
||||||
|
|
||||||
local newGenFiles oldGenFiles
|
local newGenFiles oldGenFiles
|
||||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||||
oldGenFiles="$(readlink -e "$oldGenPath/home-files")"
|
oldGenFiles="$(readlink -e "$oldGenPath/home-files")"
|
||||||
|
|
||||||
# Apply the cleanup script on each leaf in the old
|
# Apply the cleanup script on each leaf in the old
|
||||||
# generation. The find command below will print the
|
# generation. The find command below will print the
|
||||||
# relative path of the entry.
|
# relative path of the entry.
|
||||||
find "$oldGenFiles" '(' -type f -or -type l ')' -printf '%P\0' \
|
find "$oldGenFiles" '(' -type f -or -type l ')' -printf '%P\0' \
|
||||||
| xargs -0 bash ${cleanup} "$newGenFiles"
|
| xargs -0 bash ${cleanup} "$newGenFiles"
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanOldGen
|
cleanOldGen
|
||||||
linkNewGen
|
linkNewGen
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
|
|
||||||
home.activation.checkFilesChanged = lib.hm.dag.entryBefore ["linkGeneration"] (
|
home.activation.checkFilesChanged = lib.hm.dag.entryBefore [ "linkGeneration" ] (
|
||||||
let
|
let
|
||||||
homeDirArg = lib.escapeShellArg homeDirectory;
|
homeDirArg = lib.escapeShellArg homeDirectory;
|
||||||
in ''
|
in
|
||||||
|
''
|
||||||
function _cmp() {
|
function _cmp() {
|
||||||
if [[ -d $1 && -d $2 ]]; then
|
if [[ -d $1 && -d $2 ]]; then
|
||||||
diff -rq "$1" "$2" &> /dev/null
|
diff -rq "$1" "$2" &> /dev/null
|
||||||
|
|
@ -234,21 +249,25 @@ in
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
declare -A changedFiles
|
declare -A changedFiles
|
||||||
'' + lib.concatMapStrings (v:
|
''
|
||||||
|
+ lib.concatMapStrings (
|
||||||
|
v:
|
||||||
let
|
let
|
||||||
sourceArg = lib.escapeShellArg (sourceStorePath v);
|
sourceArg = lib.escapeShellArg (sourceStorePath v);
|
||||||
targetArg = lib.escapeShellArg v.target;
|
targetArg = lib.escapeShellArg v.target;
|
||||||
in ''
|
in
|
||||||
|
''
|
||||||
_cmp ${sourceArg} ${homeDirArg}/${targetArg} \
|
_cmp ${sourceArg} ${homeDirArg}/${targetArg} \
|
||||||
&& changedFiles[${targetArg}]=0 \
|
&& changedFiles[${targetArg}]=0 \
|
||||||
|| changedFiles[${targetArg}]=1
|
|| changedFiles[${targetArg}]=1
|
||||||
'') (lib.filter (v: v.onChange != "") (lib.attrValues cfg))
|
''
|
||||||
|
) (lib.filter (v: v.onChange != "") (lib.attrValues cfg))
|
||||||
+ ''
|
+ ''
|
||||||
unset -f _cmp
|
unset -f _cmp
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
|
|
||||||
home.activation.onFilesChange = lib.hm.dag.entryAfter ["linkGeneration"] (
|
home.activation.onFilesChange = lib.hm.dag.entryAfter [ "linkGeneration" ] (
|
||||||
lib.concatMapStrings (v: ''
|
lib.concatMapStrings (v: ''
|
||||||
if (( ''${changedFiles[${lib.escapeShellArg v.target}]} == 1 )); then
|
if (( ''${changedFiles[${lib.escapeShellArg v.target}]} == 1 )); then
|
||||||
if [[ -v DRY_RUN || -v VERBOSE ]]; then
|
if [[ -v DRY_RUN || -v VERBOSE ]]; then
|
||||||
|
|
@ -263,85 +282,87 @@ in
|
||||||
|
|
||||||
# Symlink directories and files that have the right execute bit.
|
# Symlink directories and files that have the right execute bit.
|
||||||
# Copy files that need their execute bit changed.
|
# Copy files that need their execute bit changed.
|
||||||
home-files = pkgs.runCommandLocal
|
home-files =
|
||||||
"home-manager-files"
|
pkgs.runCommandLocal "home-manager-files"
|
||||||
{
|
{
|
||||||
nativeBuildInputs = [ pkgs.xorg.lndir ];
|
nativeBuildInputs = [ pkgs.xorg.lndir ];
|
||||||
}
|
|
||||||
(''
|
|
||||||
mkdir -p $out
|
|
||||||
|
|
||||||
# Needed in case /nix is a symbolic link.
|
|
||||||
realOut="$(realpath -m "$out")"
|
|
||||||
|
|
||||||
function insertFile() {
|
|
||||||
local source="$1"
|
|
||||||
local relTarget="$2"
|
|
||||||
local executable="$3"
|
|
||||||
local recursive="$4"
|
|
||||||
|
|
||||||
# If the target already exists then we have a collision. Note, this
|
|
||||||
# should not happen due to the assertion found in the 'files' module.
|
|
||||||
# We therefore simply log the conflict and otherwise ignore it, mainly
|
|
||||||
# to make the `files-target-config` test work as expected.
|
|
||||||
if [[ -e "$realOut/$relTarget" ]]; then
|
|
||||||
echo "File conflict for file '$relTarget'" >&2
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Figure out the real absolute path to the target.
|
|
||||||
local target
|
|
||||||
target="$(realpath -m "$realOut/$relTarget")"
|
|
||||||
|
|
||||||
# Target path must be within $HOME.
|
|
||||||
if [[ ! $target == $realOut* ]] ; then
|
|
||||||
echo "Error installing file '$relTarget' outside \$HOME" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "$(dirname "$target")"
|
|
||||||
if [[ -d $source ]]; then
|
|
||||||
if [[ $recursive ]]; then
|
|
||||||
mkdir -p "$target"
|
|
||||||
lndir -silent "$source" "$target"
|
|
||||||
else
|
|
||||||
ln -s "$source" "$target"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
[[ -x $source ]] && isExecutable=1 || isExecutable=""
|
|
||||||
|
|
||||||
# Link the file into the home file directory if possible,
|
|
||||||
# i.e., if the executable bit of the source is the same we
|
|
||||||
# expect for the target. Otherwise, we copy the file and
|
|
||||||
# set the executable bit to the expected value.
|
|
||||||
if [[ $executable == inherit || $isExecutable == $executable ]]; then
|
|
||||||
ln -s "$source" "$target"
|
|
||||||
else
|
|
||||||
cp "$source" "$target"
|
|
||||||
|
|
||||||
if [[ $executable == inherit ]]; then
|
|
||||||
# Don't change file mode if it should match the source.
|
|
||||||
:
|
|
||||||
elif [[ $executable ]]; then
|
|
||||||
chmod +x "$target"
|
|
||||||
else
|
|
||||||
chmod -x "$target"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
'' + lib.concatStrings (
|
(
|
||||||
lib.mapAttrsToList (n: v: ''
|
''
|
||||||
insertFile ${
|
mkdir -p $out
|
||||||
lib.escapeShellArgs [
|
|
||||||
(sourceStorePath v)
|
# Needed in case /nix is a symbolic link.
|
||||||
v.target
|
realOut="$(realpath -m "$out")"
|
||||||
(if v.executable == null
|
|
||||||
then "inherit"
|
function insertFile() {
|
||||||
else toString v.executable)
|
local source="$1"
|
||||||
(toString v.recursive)
|
local relTarget="$2"
|
||||||
]}
|
local executable="$3"
|
||||||
'') cfg
|
local recursive="$4"
|
||||||
));
|
|
||||||
|
# If the target already exists then we have a collision. Note, this
|
||||||
|
# should not happen due to the assertion found in the 'files' module.
|
||||||
|
# We therefore simply log the conflict and otherwise ignore it, mainly
|
||||||
|
# to make the `files-target-config` test work as expected.
|
||||||
|
if [[ -e "$realOut/$relTarget" ]]; then
|
||||||
|
echo "File conflict for file '$relTarget'" >&2
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Figure out the real absolute path to the target.
|
||||||
|
local target
|
||||||
|
target="$(realpath -m "$realOut/$relTarget")"
|
||||||
|
|
||||||
|
# Target path must be within $HOME.
|
||||||
|
if [[ ! $target == $realOut* ]] ; then
|
||||||
|
echo "Error installing file '$relTarget' outside \$HOME" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$target")"
|
||||||
|
if [[ -d $source ]]; then
|
||||||
|
if [[ $recursive ]]; then
|
||||||
|
mkdir -p "$target"
|
||||||
|
lndir -silent "$source" "$target"
|
||||||
|
else
|
||||||
|
ln -s "$source" "$target"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
[[ -x $source ]] && isExecutable=1 || isExecutable=""
|
||||||
|
|
||||||
|
# Link the file into the home file directory if possible,
|
||||||
|
# i.e., if the executable bit of the source is the same we
|
||||||
|
# expect for the target. Otherwise, we copy the file and
|
||||||
|
# set the executable bit to the expected value.
|
||||||
|
if [[ $executable == inherit || $isExecutable == $executable ]]; then
|
||||||
|
ln -s "$source" "$target"
|
||||||
|
else
|
||||||
|
cp "$source" "$target"
|
||||||
|
|
||||||
|
if [[ $executable == inherit ]]; then
|
||||||
|
# Don't change file mode if it should match the source.
|
||||||
|
:
|
||||||
|
elif [[ $executable ]]; then
|
||||||
|
chmod +x "$target"
|
||||||
|
else
|
||||||
|
chmod -x "$target"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
''
|
||||||
|
+ lib.concatStrings (
|
||||||
|
lib.mapAttrsToList (n: v: ''
|
||||||
|
insertFile ${
|
||||||
|
lib.escapeShellArgs [
|
||||||
|
(sourceStorePath v)
|
||||||
|
v.target
|
||||||
|
(if v.executable == null then "inherit" else toString v.executable)
|
||||||
|
(toString v.recursive)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
'') cfg
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) literalExpression mkOption types;
|
inherit (lib) literalExpression mkOption types;
|
||||||
|
|
@ -112,10 +117,7 @@ let
|
||||||
options = {
|
options = {
|
||||||
layout = mkOption {
|
layout = mkOption {
|
||||||
type = with types; nullOr str;
|
type = with types; nullOr str;
|
||||||
default =
|
default = if lib.versionAtLeast config.home.stateVersion "19.09" then null else "us";
|
||||||
if lib.versionAtLeast config.home.stateVersion "19.09"
|
|
||||||
then null
|
|
||||||
else "us";
|
|
||||||
defaultText = literalExpression "null";
|
defaultText = literalExpression "null";
|
||||||
description = ''
|
description = ''
|
||||||
Keyboard layout. If `null`, then the system
|
Keyboard layout. If `null`, then the system
|
||||||
|
|
@ -137,8 +139,11 @@ let
|
||||||
|
|
||||||
options = mkOption {
|
options = mkOption {
|
||||||
type = types.listOf types.str;
|
type = types.listOf types.str;
|
||||||
default = [];
|
default = [ ];
|
||||||
example = ["grp:caps_toggle" "grp_led:scroll"];
|
example = [
|
||||||
|
"grp:caps_toggle"
|
||||||
|
"grp_led:scroll"
|
||||||
|
];
|
||||||
description = ''
|
description = ''
|
||||||
X keyboard options; layout switching goes here.
|
X keyboard options; layout switching goes here.
|
||||||
'';
|
'';
|
||||||
|
|
@ -146,10 +151,7 @@ let
|
||||||
|
|
||||||
variant = mkOption {
|
variant = mkOption {
|
||||||
type = with types; nullOr str;
|
type = with types; nullOr str;
|
||||||
default =
|
default = if lib.versionAtLeast config.home.stateVersion "19.09" then null else "";
|
||||||
if lib.versionAtLeast config.home.stateVersion "19.09"
|
|
||||||
then null
|
|
||||||
else "";
|
|
||||||
defaultText = literalExpression "null";
|
defaultText = literalExpression "null";
|
||||||
example = "colemak";
|
example = "colemak";
|
||||||
description = ''
|
description = ''
|
||||||
|
|
@ -216,7 +218,7 @@ in
|
||||||
|
|
||||||
home.language = mkOption {
|
home.language = mkOption {
|
||||||
type = languageSubModule;
|
type = languageSubModule;
|
||||||
default = {};
|
default = { };
|
||||||
description = "Language configuration.";
|
description = "Language configuration.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -254,9 +256,19 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
home.sessionVariables = mkOption {
|
home.sessionVariables = mkOption {
|
||||||
default = {};
|
default = { };
|
||||||
type = with types; lazyAttrsOf (oneOf [ str path int float ]);
|
type =
|
||||||
example = { EDITOR = "emacs"; GS_OPTIONS = "-sPAPERSIZE=a4"; };
|
with types;
|
||||||
|
lazyAttrsOf (oneOf [
|
||||||
|
str
|
||||||
|
path
|
||||||
|
int
|
||||||
|
float
|
||||||
|
]);
|
||||||
|
example = {
|
||||||
|
EDITOR = "emacs";
|
||||||
|
GS_OPTIONS = "-sPAPERSIZE=a4";
|
||||||
|
};
|
||||||
description = ''
|
description = ''
|
||||||
Environment variables to always set at login.
|
Environment variables to always set at login.
|
||||||
|
|
||||||
|
|
@ -352,14 +364,18 @@ in
|
||||||
|
|
||||||
home.packages = mkOption {
|
home.packages = mkOption {
|
||||||
type = types.listOf types.package;
|
type = types.listOf types.package;
|
||||||
default = [];
|
default = [ ];
|
||||||
description = "The set of packages to appear in the user environment.";
|
description = "The set of packages to appear in the user environment.";
|
||||||
};
|
};
|
||||||
|
|
||||||
home.extraOutputsToInstall = mkOption {
|
home.extraOutputsToInstall = mkOption {
|
||||||
type = types.listOf types.str;
|
type = types.listOf types.str;
|
||||||
default = [];
|
default = [ ];
|
||||||
example = [ "doc" "info" "devdoc" ];
|
example = [
|
||||||
|
"doc"
|
||||||
|
"info"
|
||||||
|
"devdoc"
|
||||||
|
];
|
||||||
description = ''
|
description = ''
|
||||||
List of additional package outputs of the packages
|
List of additional package outputs of the packages
|
||||||
{var}`home.packages` that should be installed into
|
{var}`home.packages` that should be installed into
|
||||||
|
|
@ -391,7 +407,7 @@ in
|
||||||
|
|
||||||
home.activation = mkOption {
|
home.activation = mkOption {
|
||||||
type = lib.hm.types.dagOf types.str;
|
type = lib.hm.types.dagOf types.str;
|
||||||
default = {};
|
default = { };
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
{
|
{
|
||||||
myActivationAction = lib.hm.dag.entryAfter ["writeBoundary"] '''
|
myActivationAction = lib.hm.dag.entryAfter ["writeBoundary"] '''
|
||||||
|
|
@ -518,41 +534,39 @@ in
|
||||||
let
|
let
|
||||||
hmRelease = config.home.version.release;
|
hmRelease = config.home.version.release;
|
||||||
nixpkgsRelease = lib.trivial.release;
|
nixpkgsRelease = lib.trivial.release;
|
||||||
releaseMismatch =
|
releaseMismatch = config.home.enableNixpkgsReleaseCheck && hmRelease != nixpkgsRelease;
|
||||||
config.home.enableNixpkgsReleaseCheck
|
|
||||||
&& hmRelease != nixpkgsRelease;
|
|
||||||
in
|
in
|
||||||
lib.optional releaseMismatch ''
|
lib.optional releaseMismatch ''
|
||||||
You are using
|
You are using
|
||||||
|
|
||||||
Home Manager version ${hmRelease} and
|
Home Manager version ${hmRelease} and
|
||||||
Nixpkgs version ${nixpkgsRelease}.
|
Nixpkgs version ${nixpkgsRelease}.
|
||||||
|
|
||||||
Using mismatched versions is likely to cause errors and unexpected
|
Using mismatched versions is likely to cause errors and unexpected
|
||||||
behavior. It is therefore highly recommended to use a release of Home
|
behavior. It is therefore highly recommended to use a release of Home
|
||||||
Manager that corresponds with your chosen release of Nixpkgs.
|
Manager that corresponds with your chosen release of Nixpkgs.
|
||||||
|
|
||||||
If you insist then you can disable this warning by adding
|
If you insist then you can disable this warning by adding
|
||||||
|
|
||||||
home.enableNixpkgsReleaseCheck = false;
|
home.enableNixpkgsReleaseCheck = false;
|
||||||
|
|
||||||
to your configuration.
|
to your configuration.
|
||||||
'';
|
'';
|
||||||
|
|
||||||
home.username =
|
home.username = lib.mkIf (lib.versionOlder config.home.stateVersion "20.09") (
|
||||||
lib.mkIf (lib.versionOlder config.home.stateVersion "20.09")
|
lib.mkDefault (builtins.getEnv "USER")
|
||||||
(lib.mkDefault (builtins.getEnv "USER"));
|
);
|
||||||
home.homeDirectory =
|
home.homeDirectory = lib.mkIf (lib.versionOlder config.home.stateVersion "20.09") (
|
||||||
lib.mkIf (lib.versionOlder config.home.stateVersion "20.09")
|
lib.mkDefault (builtins.getEnv "HOME")
|
||||||
(lib.mkDefault (builtins.getEnv "HOME"));
|
);
|
||||||
|
|
||||||
home.profileDirectory =
|
home.profileDirectory =
|
||||||
if config.submoduleSupport.enable
|
if config.submoduleSupport.enable && config.submoduleSupport.externalPackageInstall then
|
||||||
&& config.submoduleSupport.externalPackageInstall
|
"/etc/profiles/per-user/${cfg.username}"
|
||||||
then "/etc/profiles/per-user/${cfg.username}"
|
else if config.nix.enable && (config.nix.settings.use-xdg-base-directories or false) then
|
||||||
else if config.nix.enable && (config.nix.settings.use-xdg-base-directories or false)
|
"${config.xdg.stateHome}/nix/profile"
|
||||||
then "${config.xdg.stateHome}/nix/profile"
|
else
|
||||||
else cfg.homeDirectory + "/.nix-profile";
|
cfg.homeDirectory + "/.nix-profile";
|
||||||
|
|
||||||
programs.bash.shellAliases = cfg.shellAliases;
|
programs.bash.shellAliases = cfg.shellAliases;
|
||||||
programs.zsh.shellAliases = cfg.shellAliases;
|
programs.zsh.shellAliases = cfg.shellAliases;
|
||||||
|
|
@ -563,51 +577,41 @@ in
|
||||||
let
|
let
|
||||||
maybeSet = n: v: lib.optionalAttrs (v != null) { ${n} = v; };
|
maybeSet = n: v: lib.optionalAttrs (v != null) { ${n} = v; };
|
||||||
in
|
in
|
||||||
(maybeSet "LANG" cfg.language.base)
|
(maybeSet "LANG" cfg.language.base)
|
||||||
//
|
// (maybeSet "LC_CTYPE" cfg.language.ctype)
|
||||||
(maybeSet "LC_CTYPE" cfg.language.ctype)
|
// (maybeSet "LC_NUMERIC" cfg.language.numeric)
|
||||||
//
|
// (maybeSet "LC_TIME" cfg.language.time)
|
||||||
(maybeSet "LC_NUMERIC" cfg.language.numeric)
|
// (maybeSet "LC_COLLATE" cfg.language.collate)
|
||||||
//
|
// (maybeSet "LC_MONETARY" cfg.language.monetary)
|
||||||
(maybeSet "LC_TIME" cfg.language.time)
|
// (maybeSet "LC_MESSAGES" cfg.language.messages)
|
||||||
//
|
// (maybeSet "LC_PAPER" cfg.language.paper)
|
||||||
(maybeSet "LC_COLLATE" cfg.language.collate)
|
// (maybeSet "LC_NAME" cfg.language.name)
|
||||||
//
|
// (maybeSet "LC_ADDRESS" cfg.language.address)
|
||||||
(maybeSet "LC_MONETARY" cfg.language.monetary)
|
// (maybeSet "LC_TELEPHONE" cfg.language.telephone)
|
||||||
//
|
// (maybeSet "LC_MEASUREMENT" cfg.language.measurement);
|
||||||
(maybeSet "LC_MESSAGES" cfg.language.messages)
|
|
||||||
//
|
|
||||||
(maybeSet "LC_PAPER" cfg.language.paper)
|
|
||||||
//
|
|
||||||
(maybeSet "LC_NAME" cfg.language.name)
|
|
||||||
//
|
|
||||||
(maybeSet "LC_ADDRESS" cfg.language.address)
|
|
||||||
//
|
|
||||||
(maybeSet "LC_TELEPHONE" cfg.language.telephone)
|
|
||||||
//
|
|
||||||
(maybeSet "LC_MEASUREMENT" cfg.language.measurement);
|
|
||||||
|
|
||||||
# Provide a file holding all session variables.
|
# Provide a file holding all session variables.
|
||||||
home.sessionVariablesPackage = pkgs.writeTextFile {
|
home.sessionVariablesPackage = pkgs.writeTextFile {
|
||||||
name = "hm-session-vars.sh";
|
name = "hm-session-vars.sh";
|
||||||
destination = "/etc/profile.d/hm-session-vars.sh";
|
destination = "/etc/profile.d/hm-session-vars.sh";
|
||||||
text = ''
|
text =
|
||||||
# Only source this once.
|
''
|
||||||
if [ -n "$__HM_SESS_VARS_SOURCED" ]; then return; fi
|
# Only source this once.
|
||||||
export __HM_SESS_VARS_SOURCED=1
|
if [ -n "$__HM_SESS_VARS_SOURCED" ]; then return; fi
|
||||||
|
export __HM_SESS_VARS_SOURCED=1
|
||||||
|
|
||||||
${config.lib.shell.exportAll cfg.sessionVariables}
|
${config.lib.shell.exportAll cfg.sessionVariables}
|
||||||
'' + lib.concatStringsSep "\n"
|
''
|
||||||
(lib.mapAttrsToList
|
+ lib.concatStringsSep "\n" (
|
||||||
(env: values: config.lib.shell.export
|
lib.mapAttrsToList (
|
||||||
env
|
env: values: config.lib.shell.export env (config.lib.shell.prependToVar ":" env values)
|
||||||
(config.lib.shell.prependToVar ":" env values))
|
) cfg.sessionSearchVariables
|
||||||
cfg.sessionSearchVariables) + "\n"
|
)
|
||||||
|
+ "\n"
|
||||||
+ cfg.sessionVariablesExtra;
|
+ cfg.sessionVariablesExtra;
|
||||||
};
|
};
|
||||||
|
|
||||||
home.sessionSearchVariables.PATH =
|
home.sessionSearchVariables.PATH = lib.mkIf (cfg.sessionPath != [ ]) cfg.sessionPath;
|
||||||
lib.mkIf (cfg.sessionPath != [ ]) cfg.sessionPath;
|
|
||||||
|
|
||||||
home.packages = [ config.home.sessionVariablesPackage ];
|
home.packages = [ config.home.sessionVariablesPackage ];
|
||||||
|
|
||||||
|
|
@ -638,9 +642,8 @@ in
|
||||||
# In case the user has moved from a user-install of Home Manager
|
# In case the user has moved from a user-install of Home Manager
|
||||||
# to a submodule managed one we attempt to uninstall the
|
# to a submodule managed one we attempt to uninstall the
|
||||||
# `home-manager-path` package if it is installed.
|
# `home-manager-path` package if it is installed.
|
||||||
home.activation.installPackages = lib.hm.dag.entryAfter ["writeBoundary"] (
|
home.activation.installPackages = lib.hm.dag.entryAfter [ "writeBoundary" ] (
|
||||||
if config.submoduleSupport.externalPackageInstall
|
if config.submoduleSupport.externalPackageInstall then
|
||||||
then
|
|
||||||
''
|
''
|
||||||
nixProfileRemove home-manager-path
|
nixProfileRemove home-manager-path
|
||||||
''
|
''
|
||||||
|
|
@ -681,62 +684,66 @@ in
|
||||||
# in the `hm-modules` text domain.
|
# in the `hm-modules` text domain.
|
||||||
lib.bash.initHomeManagerLib =
|
lib.bash.initHomeManagerLib =
|
||||||
let
|
let
|
||||||
domainDir = pkgs.runCommand "hm-modules-messages" {
|
domainDir =
|
||||||
nativeBuildInputs = [ pkgs.buildPackages.gettext ];
|
pkgs.runCommand "hm-modules-messages"
|
||||||
} ''
|
{
|
||||||
for path in ${./po}/*.po; do
|
nativeBuildInputs = [ pkgs.buildPackages.gettext ];
|
||||||
lang="''${path##*/}"
|
}
|
||||||
lang="''${lang%%.*}"
|
''
|
||||||
mkdir -p "$out/$lang/LC_MESSAGES"
|
for path in ${./po}/*.po; do
|
||||||
msgfmt -o "$out/$lang/LC_MESSAGES/hm-modules.mo" "$path"
|
lang="''${path##*/}"
|
||||||
done
|
lang="''${lang%%.*}"
|
||||||
'';
|
mkdir -p "$out/$lang/LC_MESSAGES"
|
||||||
|
msgfmt -o "$out/$lang/LC_MESSAGES/hm-modules.mo" "$path"
|
||||||
|
done
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
''
|
''
|
||||||
export TEXTDOMAIN=hm-modules
|
export TEXTDOMAIN=hm-modules
|
||||||
export TEXTDOMAINDIR=${domainDir}
|
export TEXTDOMAINDIR=${domainDir}
|
||||||
source ${../lib/bash/home-manager.sh}
|
source ${../lib/bash/home-manager.sh}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
home.activationPackage =
|
home.activationPackage =
|
||||||
let
|
let
|
||||||
mkCmd = res: ''
|
mkCmd = res: ''
|
||||||
_iNote "Activating %s" "${res.name}"
|
_iNote "Activating %s" "${res.name}"
|
||||||
${res.data}
|
${res.data}
|
||||||
'';
|
'';
|
||||||
sortedCommands = lib.hm.dag.topoSort cfg.activation;
|
sortedCommands = lib.hm.dag.topoSort cfg.activation;
|
||||||
activationCmds =
|
activationCmds =
|
||||||
if sortedCommands ? result then
|
if sortedCommands ? result then
|
||||||
lib.concatStringsSep "\n" (map mkCmd sortedCommands.result)
|
lib.concatStringsSep "\n" (map mkCmd sortedCommands.result)
|
||||||
else
|
else
|
||||||
abort ("Dependency cycle in activation script: "
|
abort ("Dependency cycle in activation script: " + builtins.toJSON sortedCommands);
|
||||||
+ builtins.toJSON sortedCommands);
|
|
||||||
|
|
||||||
# Programs that always should be available on the activation
|
# Programs that always should be available on the activation
|
||||||
# script's PATH.
|
# script's PATH.
|
||||||
activationBinPaths = lib.makeBinPath (
|
activationBinPaths =
|
||||||
with pkgs; [
|
lib.makeBinPath (
|
||||||
bash
|
with pkgs;
|
||||||
coreutils
|
[
|
||||||
diffutils # For `cmp` and `diff`.
|
bash
|
||||||
findutils
|
coreutils
|
||||||
gettext
|
diffutils # For `cmp` and `diff`.
|
||||||
gnugrep
|
findutils
|
||||||
gnused
|
gettext
|
||||||
jq
|
gnugrep
|
||||||
ncurses # For `tput`.
|
gnused
|
||||||
]
|
jq
|
||||||
++ config.home.extraActivationPath
|
ncurses # For `tput`.
|
||||||
)
|
]
|
||||||
+ (
|
++ config.home.extraActivationPath
|
||||||
# Add path of the Nix binaries, if a Nix package is configured, then
|
)
|
||||||
# use that one, otherwise grab the path of the nix-env tool.
|
+ (
|
||||||
if config.nix.enable && config.nix.package != null then
|
# Add path of the Nix binaries, if a Nix package is configured, then
|
||||||
":${config.nix.package}/bin"
|
# use that one, otherwise grab the path of the nix-env tool.
|
||||||
else
|
if config.nix.enable && config.nix.package != null then
|
||||||
":$(${pkgs.coreutils}/bin/dirname $(${pkgs.coreutils}/bin/readlink -m $(type -p nix-env)))"
|
":${config.nix.package}/bin"
|
||||||
)
|
else
|
||||||
+ lib.optionalString (!cfg.emptyActivationPath) "\${PATH:+:}$PATH";
|
":$(${pkgs.coreutils}/bin/dirname $(${pkgs.coreutils}/bin/readlink -m $(type -p nix-env)))"
|
||||||
|
)
|
||||||
|
+ lib.optionalString (!cfg.emptyActivationPath) "\${PATH:+:}$PATH";
|
||||||
|
|
||||||
activationScript = pkgs.writeShellScript "activation-script" ''
|
activationScript = pkgs.writeShellScript "activation-script" ''
|
||||||
set -eu
|
set -eu
|
||||||
|
|
@ -770,29 +777,28 @@ in
|
||||||
''}
|
''}
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
pkgs.runCommand
|
pkgs.runCommand "home-manager-generation"
|
||||||
"home-manager-generation"
|
{
|
||||||
{
|
preferLocalBuild = true;
|
||||||
preferLocalBuild = true;
|
}
|
||||||
}
|
''
|
||||||
''
|
mkdir -p $out
|
||||||
mkdir -p $out
|
|
||||||
|
|
||||||
echo "${config.home.version.full}" > $out/hm-version
|
echo "${config.home.version.full}" > $out/hm-version
|
||||||
|
|
||||||
cp ${activationScript} $out/activate
|
cp ${activationScript} $out/activate
|
||||||
|
|
||||||
mkdir $out/bin
|
mkdir $out/bin
|
||||||
ln -s $out/activate $out/bin/home-manager-generation
|
ln -s $out/activate $out/bin/home-manager-generation
|
||||||
|
|
||||||
substituteInPlace $out/activate \
|
substituteInPlace $out/activate \
|
||||||
--subst-var-by GENERATION_DIR $out
|
--subst-var-by GENERATION_DIR $out
|
||||||
|
|
||||||
ln -s ${config.home-files} $out/home-files
|
ln -s ${config.home-files} $out/home-files
|
||||||
ln -s ${cfg.path} $out/home-path
|
ln -s ${cfg.path} $out/home-path
|
||||||
|
|
||||||
${cfg.extraBuilderCommands}
|
${cfg.extraBuilderCommands}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
home.path = pkgs.buildEnv {
|
home.path = pkgs.buildEnv {
|
||||||
name = "home-manager-path";
|
name = "home-manager-path";
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,65 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.i18n.inputMethod;
|
cfg = config.i18n.inputMethod;
|
||||||
|
|
||||||
gtk2Cache = pkgs.runCommandLocal "gtk2-immodule.cache" {
|
gtk2Cache =
|
||||||
buildInputs = [ pkgs.gtk2 cfg.package ];
|
pkgs.runCommandLocal "gtk2-immodule.cache"
|
||||||
} ''
|
{
|
||||||
mkdir -p $out/etc/gtk-2.0/
|
buildInputs = [
|
||||||
GTK_PATH=${cfg.package}/lib/gtk-2.0/ \
|
pkgs.gtk2
|
||||||
gtk-query-immodules-2.0 > $out/etc/gtk-2.0/immodules.cache
|
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" {
|
gtk3Cache =
|
||||||
buildInputs = [ pkgs.gtk3 cfg.package ];
|
pkgs.runCommandLocal "gtk3-immodule.cache"
|
||||||
} ''
|
{
|
||||||
mkdir -p $out/etc/gtk-3.0/
|
buildInputs = [
|
||||||
GTK_PATH=${cfg.package}/lib/gtk-3.0/ \
|
pkgs.gtk3
|
||||||
gtk-query-immodules-3.0 > $out/etc/gtk-3.0/immodules.cache
|
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 {
|
in
|
||||||
imports = [ ./fcitx5.nix ./hime.nix ./kime.nix ./nabi.nix ./uim.nix ];
|
{
|
||||||
|
imports = [
|
||||||
|
./fcitx5.nix
|
||||||
|
./hime.nix
|
||||||
|
./kime.nix
|
||||||
|
./nabi.nix
|
||||||
|
./uim.nix
|
||||||
|
];
|
||||||
|
|
||||||
options.i18n = {
|
options.i18n = {
|
||||||
inputMethod = {
|
inputMethod = {
|
||||||
enabled = lib.mkOption {
|
enabled = lib.mkOption {
|
||||||
type = lib.types.nullOr
|
type = lib.types.nullOr (
|
||||||
(lib.types.enum [ "fcitx" "fcitx5" "nabi" "uim" "hime" "kime" ]);
|
lib.types.enum [
|
||||||
|
"fcitx"
|
||||||
|
"fcitx5"
|
||||||
|
"nabi"
|
||||||
|
"uim"
|
||||||
|
"hime"
|
||||||
|
"kime"
|
||||||
|
]
|
||||||
|
);
|
||||||
default = null;
|
default = null;
|
||||||
example = "fcitx5";
|
example = "fcitx5";
|
||||||
description = ''
|
description = ''
|
||||||
|
|
@ -73,15 +105,18 @@ in {
|
||||||
|
|
||||||
config = lib.mkIf (cfg.enabled != null) {
|
config = lib.mkIf (cfg.enabled != null) {
|
||||||
assertions = [
|
assertions = [
|
||||||
(lib.hm.assertions.assertPlatform "i18n.inputMethod" pkgs
|
(lib.hm.assertions.assertPlatform "i18n.inputMethod" pkgs lib.platforms.linux)
|
||||||
lib.platforms.linux)
|
|
||||||
{
|
{
|
||||||
assertion = cfg.enabled != "fcitx";
|
assertion = cfg.enabled != "fcitx";
|
||||||
message = "fcitx has been removed, please use fcitx5 instead";
|
message = "fcitx has been removed, please use fcitx5 instead";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
home.packages = [ cfg.package gtk2Cache gtk3Cache ];
|
home.packages = [
|
||||||
|
cfg.package
|
||||||
|
gtk2Cache
|
||||||
|
gtk3Cache
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
meta.maintainers = [ lib.hm.maintainers.kranzes ];
|
meta.maintainers = [ lib.hm.maintainers.kranzes ];
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
im = config.i18n.inputMethod;
|
im = config.i18n.inputMethod;
|
||||||
cfg = im.fcitx5;
|
cfg = im.fcitx5;
|
||||||
fcitx5Package = cfg.fcitx5-with-addons.override { inherit (cfg) addons; };
|
fcitx5Package = cfg.fcitx5-with-addons.override { inherit (cfg) addons; };
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
i18n.inputMethod.fcitx5 = {
|
i18n.inputMethod.fcitx5 = {
|
||||||
fcitx5-with-addons = lib.mkOption {
|
fcitx5-with-addons = lib.mkOption {
|
||||||
|
|
@ -38,17 +44,18 @@ in {
|
||||||
i18n.inputMethod.package = fcitx5Package;
|
i18n.inputMethod.package = fcitx5Package;
|
||||||
|
|
||||||
home = {
|
home = {
|
||||||
sessionVariables = {
|
sessionVariables =
|
||||||
GLFW_IM_MODULE = "ibus"; # IME support in kitty
|
{
|
||||||
SDL_IM_MODULE = "fcitx";
|
GLFW_IM_MODULE = "ibus"; # IME support in kitty
|
||||||
XMODIFIERS = "@im=fcitx";
|
SDL_IM_MODULE = "fcitx";
|
||||||
} // lib.optionalAttrs (!cfg.waylandFrontend) {
|
XMODIFIERS = "@im=fcitx";
|
||||||
GTK_IM_MODULE = "fcitx";
|
}
|
||||||
QT_IM_MODULE = "fcitx";
|
// lib.optionalAttrs (!cfg.waylandFrontend) {
|
||||||
};
|
GTK_IM_MODULE = "fcitx";
|
||||||
|
QT_IM_MODULE = "fcitx";
|
||||||
|
};
|
||||||
|
|
||||||
sessionSearchVariables.QT_PLUGIN_PATH =
|
sessionSearchVariables.QT_PLUGIN_PATH = [ "${fcitx5Package}/${pkgs.qt6.qtbase.qtPluginPrefix}" ];
|
||||||
[ "${fcitx5Package}/${pkgs.qt6.qtbase.qtPluginPrefix}" ];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.user.services.fcitx5-daemon = {
|
systemd.user.services.fcitx5-daemon = {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
config = lib.mkIf (config.i18n.inputMethod.enabled == "hime") {
|
config = lib.mkIf (config.i18n.inputMethod.enabled == "hime") {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,22 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) literalExpression mkIf mkOption mkRemovedOptionModule types;
|
inherit (lib)
|
||||||
|
literalExpression
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
mkRemovedOptionModule
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.i18n.inputMethod.kime;
|
cfg = config.i18n.inputMethod.kime;
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
imports = [
|
imports = [
|
||||||
(mkRemovedOptionModule [ "i18n" "inputMethod" "kime" "config" ] ''
|
(mkRemovedOptionModule [ "i18n" "inputMethod" "kime" "config" ] ''
|
||||||
Please use 'i18n.inputMethod.kime.extraConfig' instead.
|
Please use 'i18n.inputMethod.kime.extraConfig' instead.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
config = lib.mkIf (config.i18n.inputMethod.enabled == "nabi") {
|
config = lib.mkIf (config.i18n.inputMethod.enabled == "nabi") {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,25 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let cfg = config.i18n.inputMethod.uim;
|
let
|
||||||
in {
|
cfg = config.i18n.inputMethod.uim;
|
||||||
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
|
|
||||||
i18n.inputMethod.uim = {
|
i18n.inputMethod.uim = {
|
||||||
toolbar = lib.mkOption {
|
toolbar = lib.mkOption {
|
||||||
type =
|
type = lib.types.enum [
|
||||||
lib.types.enum [ "gtk" "gtk3" "gtk-systray" "gtk3-systray" "qt4" ];
|
"gtk"
|
||||||
|
"gtk3"
|
||||||
|
"gtk-systray"
|
||||||
|
"gtk3-systray"
|
||||||
|
"qt4"
|
||||||
|
];
|
||||||
default = "gtk";
|
default = "gtk";
|
||||||
example = "gtk-systray";
|
example = "gtk-systray";
|
||||||
description = ''
|
description = ''
|
||||||
|
|
@ -32,11 +44,12 @@ in {
|
||||||
Description = "Uim input method editor";
|
Description = "Uim input method editor";
|
||||||
PartOf = [ "graphical-session.desktop" ];
|
PartOf = [ "graphical-session.desktop" ];
|
||||||
};
|
};
|
||||||
Service.ExecStart = toString
|
Service.ExecStart = toString (
|
||||||
(pkgs.writeShellScript "start-uim-xim-and-uim-toolbar" ''
|
pkgs.writeShellScript "start-uim-xim-and-uim-toolbar" ''
|
||||||
${pkgs.uim}/bin/uim-xim &
|
${pkgs.uim}/bin/uim-xim &
|
||||||
${pkgs.uim}/bin/uim-toolbar-${cfg.toolbar}
|
${pkgs.uim}/bin/uim-toolbar-${cfg.toolbar}
|
||||||
'');
|
''
|
||||||
|
);
|
||||||
Install.WantedBy = [ "graphical-session.target" ];
|
Install.WantedBy = [ "graphical-session.target" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (pkgs.stdenv.hostPlatform) isDarwin;
|
inherit (pkgs.stdenv.hostPlatform) isDarwin;
|
||||||
|
|
@ -8,45 +13,48 @@ let
|
||||||
labelPrefix = "org.nix-community.home.";
|
labelPrefix = "org.nix-community.home.";
|
||||||
dstDir = "${config.home.homeDirectory}/Library/LaunchAgents";
|
dstDir = "${config.home.homeDirectory}/Library/LaunchAgents";
|
||||||
|
|
||||||
launchdConfig = { config, name, ... }: {
|
launchdConfig =
|
||||||
options = {
|
{ config, name, ... }:
|
||||||
enable = lib.mkEnableOption name;
|
{
|
||||||
config = lib.mkOption {
|
options = {
|
||||||
type = lib.types.submodule (import ./launchd.nix);
|
enable = lib.mkEnableOption name;
|
||||||
default = { };
|
config = lib.mkOption {
|
||||||
example = lib.literalExpression ''
|
type = lib.types.submodule (import ./launchd.nix);
|
||||||
{
|
default = { };
|
||||||
ProgramArguments = [ "/usr/bin/say" "Good afternoon" ];
|
example = lib.literalExpression ''
|
||||||
StartCalendarInterval = [
|
{
|
||||||
{
|
ProgramArguments = [ "/usr/bin/say" "Good afternoon" ];
|
||||||
Hour = 12;
|
StartCalendarInterval = [
|
||||||
Minute = 0;
|
{
|
||||||
}
|
Hour = 12;
|
||||||
];
|
Minute = 0;
|
||||||
}
|
}
|
||||||
'';
|
];
|
||||||
description = ''
|
}
|
||||||
Define a launchd job. See {manpage}`launchd.plist(5)` for details.
|
'';
|
||||||
'';
|
description = ''
|
||||||
|
Define a launchd job. See {manpage}`launchd.plist(5)` for details.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
config.Label = lib.mkDefault "${labelPrefix}${name}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = { config.Label = lib.mkDefault "${labelPrefix}${name}"; };
|
|
||||||
};
|
|
||||||
|
|
||||||
toAgent = config: pkgs.writeText "${config.Label}.plist" (toPlist { } config);
|
toAgent = config: pkgs.writeText "${config.Label}.plist" (toPlist { } config);
|
||||||
|
|
||||||
agentPlists = lib.mapAttrs'
|
agentPlists = lib.mapAttrs' (n: v: lib.nameValuePair "${v.config.Label}.plist" (toAgent v.config)) (
|
||||||
(n: v: lib.nameValuePair "${v.config.Label}.plist" (toAgent v.config))
|
lib.filterAttrs (n: v: v.enable) cfg.agents
|
||||||
(lib.filterAttrs (n: v: v.enable) cfg.agents);
|
);
|
||||||
|
|
||||||
agentsDrv = pkgs.runCommand "home-manager-agents" { } ''
|
agentsDrv = pkgs.runCommand "home-manager-agents" { } ''
|
||||||
mkdir -p "$out"
|
mkdir -p "$out"
|
||||||
|
|
||||||
declare -A plists
|
declare -A plists
|
||||||
plists=(${
|
plists=(${
|
||||||
lib.concatStringsSep " "
|
lib.concatStringsSep " " (lib.mapAttrsToList (name: value: "['${name}']='${value}'") agentPlists)
|
||||||
(lib.mapAttrsToList (name: value: "['${name}']='${value}'") agentPlists)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
for dest in "''${!plists[@]}"; do
|
for dest in "''${!plists[@]}"; do
|
||||||
|
|
@ -54,8 +62,12 @@ let
|
||||||
ln -s "$src" "$out/$dest"
|
ln -s "$src" "$out/$dest"
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
in {
|
in
|
||||||
meta.maintainers = with lib.maintainers; [ khaneliman midchildan ];
|
{
|
||||||
|
meta.maintainers = with lib.maintainers; [
|
||||||
|
khaneliman
|
||||||
|
midchildan
|
||||||
|
];
|
||||||
|
|
||||||
options.launchd = {
|
options.launchd = {
|
||||||
enable = lib.mkOption {
|
enable = lib.mkOption {
|
||||||
|
|
@ -77,12 +89,16 @@ in {
|
||||||
|
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
{
|
{
|
||||||
assertions = [{
|
assertions = [
|
||||||
assertion = (cfg.enable && agentPlists != { }) -> isDarwin;
|
{
|
||||||
message =
|
assertion = (cfg.enable && agentPlists != { }) -> isDarwin;
|
||||||
let names = lib.concatStringsSep ", " (lib.attrNames agentPlists);
|
message =
|
||||||
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 {
|
(lib.mkIf isDarwin {
|
||||||
|
|
@ -94,170 +110,170 @@ in {
|
||||||
# because it needs to be owned by the user running it.
|
# because it needs to be owned by the user running it.
|
||||||
home.activation.setupLaunchAgents =
|
home.activation.setupLaunchAgents =
|
||||||
lib.hm.dag.entryAfter [ "writeBoundary" ] # Bash
|
lib.hm.dag.entryAfter [ "writeBoundary" ] # Bash
|
||||||
''
|
''
|
||||||
# Disable errexit to ensure we process all agents even if some fail
|
# Disable errexit to ensure we process all agents even if some fail
|
||||||
set +e
|
set +e
|
||||||
|
|
||||||
# Stop an agent if it's running
|
# Stop an agent if it's running
|
||||||
bootoutAgent() {
|
bootoutAgent() {
|
||||||
local domain="$1"
|
local domain="$1"
|
||||||
local agentName="$2"
|
local agentName="$2"
|
||||||
|
|
||||||
verboseEcho "Stopping agent '$domain/$agentName'..."
|
verboseEcho "Stopping agent '$domain/$agentName'..."
|
||||||
local bootout_output
|
local bootout_output
|
||||||
bootout_output=$(run /bin/launchctl bootout "$domain/$agentName" 2>&1) || {
|
bootout_output=$(run /bin/launchctl bootout "$domain/$agentName" 2>&1) || {
|
||||||
# Only show warning if it's not the common "No such process" error
|
# Only show warning if it's not the common "No such process" error
|
||||||
if [[ "$bootout_output" != *"No such process"* ]]; then
|
if [[ "$bootout_output" != *"No such process"* ]]; then
|
||||||
warnEcho "Failed to stop agent '$domain/$agentName': $bootout_output"
|
warnEcho "Failed to stop agent '$domain/$agentName': $bootout_output"
|
||||||
else
|
else
|
||||||
verboseEcho "Agent '$domain/$agentName' was not running"
|
verboseEcho "Agent '$domain/$agentName' was not running"
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Give the system a moment to fully unload the agent
|
||||||
|
sleep 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Give the system a moment to fully unload the agent
|
installAndBootstrapAgent() {
|
||||||
sleep 1
|
local srcPath="$1"
|
||||||
}
|
local dstPath="$2"
|
||||||
|
local domain="$3"
|
||||||
|
local agentName="$4"
|
||||||
|
|
||||||
installAndBootstrapAgent() {
|
verboseEcho "Installing agent file to $dstPath"
|
||||||
local srcPath="$1"
|
if ! run install -Dm444 -T "$srcPath" "$dstPath"; then
|
||||||
local dstPath="$2"
|
errorEcho "Failed to install agent file for '$agentName'"
|
||||||
local domain="$3"
|
return 1
|
||||||
local agentName="$4"
|
|
||||||
|
|
||||||
verboseEcho "Installing agent file to $dstPath"
|
|
||||||
if ! run install -Dm444 -T "$srcPath" "$dstPath"; then
|
|
||||||
errorEcho "Failed to install agent file for '$agentName'"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
verboseEcho "Starting agent '$domain/$agentName'"
|
|
||||||
local bootstrap_output
|
|
||||||
bootstrap_output=$(run /bin/launchctl bootstrap "$domain" "$dstPath" 2>&1) || {
|
|
||||||
local error_code=$?
|
|
||||||
|
|
||||||
if [[ "$bootstrap_output" == *"Bootstrap failed: 5: Input/output error"* ]]; then
|
|
||||||
errorEcho "Failed to start agent '$domain/$agentName' with I/O error (code 5)"
|
|
||||||
errorEcho "This typically happens when the agent wasn't unloaded before attempting to bootstrap the new agent."
|
|
||||||
else
|
|
||||||
errorEcho "Failed to start agent '$domain/$agentName' with error: $bootstrap_output"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return 1
|
verboseEcho "Starting agent '$domain/$agentName'"
|
||||||
}
|
local bootstrap_output
|
||||||
|
bootstrap_output=$(run /bin/launchctl bootstrap "$domain" "$dstPath" 2>&1) || {
|
||||||
|
local error_code=$?
|
||||||
|
|
||||||
verboseEcho "Successfully started agent '$domain/$agentName'"
|
if [[ "$bootstrap_output" == *"Bootstrap failed: 5: Input/output error"* ]]; then
|
||||||
return 0
|
errorEcho "Failed to start agent '$domain/$agentName' with I/O error (code 5)"
|
||||||
}
|
errorEcho "This typically happens when the agent wasn't unloaded before attempting to bootstrap the new agent."
|
||||||
|
else
|
||||||
|
errorEcho "Failed to start agent '$domain/$agentName' with error: $bootstrap_output"
|
||||||
|
fi
|
||||||
|
|
||||||
processAgent() {
|
return 1
|
||||||
local srcPath="$1"
|
}
|
||||||
local dstDir="$2"
|
|
||||||
local domain="$3"
|
|
||||||
|
|
||||||
local agentFile="''${srcPath##*/}"
|
verboseEcho "Successfully started agent '$domain/$agentName'"
|
||||||
local agentName="''${agentFile%.plist}"
|
|
||||||
local dstPath="$dstDir/$agentFile"
|
|
||||||
|
|
||||||
# Skip if unchanged
|
|
||||||
if cmp -s "$srcPath" "$dstPath"; then
|
|
||||||
verboseEcho "Agent '$agentName' is already up-to-date"
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
}
|
||||||
|
|
||||||
verboseEcho "Processing agent '$agentName'"
|
processAgent() {
|
||||||
|
local srcPath="$1"
|
||||||
|
local dstDir="$2"
|
||||||
|
local domain="$3"
|
||||||
|
|
||||||
# Stop/Unload agent if it's already running
|
local agentFile="''${srcPath##*/}"
|
||||||
if [[ -f "$dstPath" ]]; then
|
local agentName="''${agentFile%.plist}"
|
||||||
|
local dstPath="$dstDir/$agentFile"
|
||||||
|
|
||||||
|
# Skip if unchanged
|
||||||
|
if cmp -s "$srcPath" "$dstPath"; then
|
||||||
|
verboseEcho "Agent '$agentName' is already up-to-date"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
verboseEcho "Processing agent '$agentName'"
|
||||||
|
|
||||||
|
# Stop/Unload agent if it's already running
|
||||||
|
if [[ -f "$dstPath" ]]; then
|
||||||
|
bootoutAgent "$domain" "$agentName"
|
||||||
|
fi
|
||||||
|
|
||||||
|
installAndBootstrapAgent "$srcPath" "$dstPath" "$domain" "$agentName"
|
||||||
|
# Note: We continue processing even if this agent fails
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAgent() {
|
||||||
|
local srcPath="$1"
|
||||||
|
local dstDir="$2"
|
||||||
|
local newDir="$3"
|
||||||
|
local domain="$4"
|
||||||
|
|
||||||
|
local agentFile="''${srcPath##*/}"
|
||||||
|
local agentName="''${agentFile%.plist}"
|
||||||
|
local dstPath="$dstDir/$agentFile"
|
||||||
|
|
||||||
|
if [[ -e "$newDir/$agentFile" ]]; then
|
||||||
|
verboseEcho "Agent '$agentName' still exists in new generation, skipping cleanup"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -e "$dstPath" ]]; then
|
||||||
|
verboseEcho "Agent file '$dstPath' already removed"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! cmp -s "$srcPath" "$dstPath"; then
|
||||||
|
warnEcho "Skipping deletion of '$dstPath', since its contents have diverged"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stop and remove the agent
|
||||||
bootoutAgent "$domain" "$agentName"
|
bootoutAgent "$domain" "$agentName"
|
||||||
fi
|
|
||||||
|
|
||||||
installAndBootstrapAgent "$srcPath" "$dstPath" "$domain" "$agentName"
|
verboseEcho "Removing agent file '$dstPath'"
|
||||||
# Note: We continue processing even if this agent fails
|
if run rm -f $VERBOSE_ARG "$dstPath"; then
|
||||||
return 0
|
verboseEcho "Successfully removed agent file for '$agentName'"
|
||||||
}
|
else
|
||||||
|
warnEcho "Failed to remove agent file '$dstPath'"
|
||||||
|
fi
|
||||||
|
|
||||||
removeAgent() {
|
|
||||||
local srcPath="$1"
|
|
||||||
local dstDir="$2"
|
|
||||||
local newDir="$3"
|
|
||||||
local domain="$4"
|
|
||||||
|
|
||||||
local agentFile="''${srcPath##*/}"
|
|
||||||
local agentName="''${agentFile%.plist}"
|
|
||||||
local dstPath="$dstDir/$agentFile"
|
|
||||||
|
|
||||||
if [[ -e "$newDir/$agentFile" ]]; then
|
|
||||||
verboseEcho "Agent '$agentName' still exists in new generation, skipping cleanup"
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
}
|
||||||
|
|
||||||
if [[ ! -e "$dstPath" ]]; then
|
setupLaunchAgents() {
|
||||||
verboseEcho "Agent file '$dstPath' already removed"
|
local oldDir newDir dstDir domain
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! cmp -s "$srcPath" "$dstPath"; then
|
newDir="$(readlink -m "$newGenPath/LaunchAgents")"
|
||||||
warnEcho "Skipping deletion of '$dstPath', since its contents have diverged"
|
dstDir=${lib.escapeShellArg dstDir}
|
||||||
return 0
|
domain="gui/$UID"
|
||||||
fi
|
|
||||||
|
|
||||||
# Stop and remove the agent
|
if [[ -n "''${oldGenPath:-}" ]]; then
|
||||||
bootoutAgent "$domain" "$agentName"
|
oldDir="$(readlink -m "$oldGenPath/LaunchAgents")"
|
||||||
|
if [[ ! -d "$oldDir" ]]; then
|
||||||
verboseEcho "Removing agent file '$dstPath'"
|
verboseEcho "No previous LaunchAgents directory found"
|
||||||
if run rm -f $VERBOSE_ARG "$dstPath"; then
|
oldDir=""
|
||||||
verboseEcho "Successfully removed agent file for '$agentName'"
|
fi
|
||||||
else
|
else
|
||||||
warnEcho "Failed to remove agent file '$dstPath'"
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
setupLaunchAgents() {
|
|
||||||
local oldDir newDir dstDir domain
|
|
||||||
|
|
||||||
newDir="$(readlink -m "$newGenPath/LaunchAgents")"
|
|
||||||
dstDir=${lib.escapeShellArg dstDir}
|
|
||||||
domain="gui/$UID"
|
|
||||||
|
|
||||||
if [[ -n "''${oldGenPath:-}" ]]; then
|
|
||||||
oldDir="$(readlink -m "$oldGenPath/LaunchAgents")"
|
|
||||||
if [[ ! -d "$oldDir" ]]; then
|
|
||||||
verboseEcho "No previous LaunchAgents directory found"
|
|
||||||
oldDir=""
|
oldDir=""
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
oldDir=""
|
verboseEcho "Setting up LaunchAgents in $dstDir"
|
||||||
|
[[ -d "$dstDir" ]] || run mkdir -p "$dstDir"
|
||||||
|
|
||||||
|
verboseEcho "Processing new/updated LaunchAgents..."
|
||||||
|
find -L "$newDir" -maxdepth 1 -name '*.plist' -type f | while read -r srcPath; do
|
||||||
|
processAgent "$srcPath" "$dstDir" "$domain"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Skip cleanup if there's no previous generation
|
||||||
|
if [[ -z "$oldDir" || ! -d "$oldDir" ]]; then
|
||||||
|
verboseEcho "LaunchAgents setup complete"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
verboseEcho "Cleaning up removed LaunchAgents..."
|
||||||
|
find -L "$oldDir" -maxdepth 1 -name '*.plist' -type f | while read -r srcPath; do
|
||||||
|
removeAgent "$srcPath" "$dstDir" "$newDir" "$domain"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
setupLaunchAgents
|
||||||
|
|
||||||
|
# Restore errexit
|
||||||
|
if [[ -o errexit ]]; then
|
||||||
|
set -e
|
||||||
fi
|
fi
|
||||||
|
'';
|
||||||
verboseEcho "Setting up LaunchAgents in $dstDir"
|
|
||||||
[[ -d "$dstDir" ]] || run mkdir -p "$dstDir"
|
|
||||||
|
|
||||||
verboseEcho "Processing new/updated LaunchAgents..."
|
|
||||||
find -L "$newDir" -maxdepth 1 -name '*.plist' -type f | while read -r srcPath; do
|
|
||||||
processAgent "$srcPath" "$dstDir" "$domain"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Skip cleanup if there's no previous generation
|
|
||||||
if [[ -z "$oldDir" || ! -d "$oldDir" ]]; then
|
|
||||||
verboseEcho "LaunchAgents setup complete"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
verboseEcho "Cleaning up removed LaunchAgents..."
|
|
||||||
find -L "$oldDir" -maxdepth 1 -name '*.plist' -type f | while read -r srcPath; do
|
|
||||||
removeAgent "$srcPath" "$dstDir" "$newDir" "$domain"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
setupLaunchAgents
|
|
||||||
|
|
||||||
# Restore errexit
|
|
||||||
if [[ -o errexit ]]; then
|
|
||||||
set -e
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,8 @@ let
|
||||||
inherit (lib) types mkOption; # added by Home Manager
|
inherit (lib) types mkOption; # added by Home Manager
|
||||||
|
|
||||||
launchdTypes = import ./types.nix { inherit config lib; };
|
launchdTypes = import ./types.nix { inherit config lib; };
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
freeformType = with types; attrsOf anything; # added by Home Manager
|
freeformType = with types; attrsOf anything; # added by Home Manager
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -82,23 +83,27 @@ in {
|
||||||
|
|
||||||
inetdCompatibility = mkOption {
|
inetdCompatibility = mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
example = { Wait = true; };
|
example = {
|
||||||
|
Wait = true;
|
||||||
|
};
|
||||||
description = ''
|
description = ''
|
||||||
The presence of this key specifies that the daemon expects to be run as if it were launched from inetd.
|
The presence of this key specifies that the daemon expects to be run as if it were launched from inetd.
|
||||||
'';
|
'';
|
||||||
type = types.nullOr (types.submodule {
|
type = types.nullOr (
|
||||||
options = {
|
types.submodule {
|
||||||
Wait = mkOption {
|
options = {
|
||||||
type = types.nullOr (types.either types.bool types.str);
|
Wait = mkOption {
|
||||||
default = null;
|
type = types.nullOr (types.either types.bool types.str);
|
||||||
description = ''
|
default = null;
|
||||||
This flag corresponds to the "wait" or "nowait" option of inetd. If true, then the listening
|
description = ''
|
||||||
socket is passed via the standard in/out/error file descriptors. If false, then `accept(2)` is
|
This flag corresponds to the "wait" or "nowait" option of inetd. If true, then the listening
|
||||||
called on behalf of the job, and the result is passed via the standard in/out/error descriptors.
|
socket is passed via the standard in/out/error file descriptors. If false, then `accept(2)` is
|
||||||
'';
|
called on behalf of the job, and the result is passed via the standard in/out/error descriptors.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
});
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
LimitLoadToHosts = mkOption {
|
LimitLoadToHosts = mkOption {
|
||||||
|
|
@ -120,7 +125,12 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
LimitLoadToSessionType = mkOption {
|
LimitLoadToSessionType = mkOption {
|
||||||
type = types.nullOr (types.oneOf [ types.str (types.listOf types.str) ]);
|
type = types.nullOr (
|
||||||
|
types.oneOf [
|
||||||
|
types.str
|
||||||
|
(types.listOf types.str)
|
||||||
|
]
|
||||||
|
);
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
This configuration file only applies to sessions of the type specified. This key is used in concert
|
This configuration file only applies to sessions of the type specified. This key is used in concert
|
||||||
|
|
@ -177,68 +187,72 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
KeepAlive = mkOption {
|
KeepAlive = mkOption {
|
||||||
type = types.nullOr (types.either types.bool (types.submodule {
|
type = types.nullOr (
|
||||||
options = {
|
types.either types.bool (
|
||||||
|
types.submodule {
|
||||||
|
options = {
|
||||||
|
|
||||||
SuccessfulExit = mkOption {
|
SuccessfulExit = mkOption {
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
If true, the job will be restarted as long as the program exits and with an exit status of zero.
|
If true, the job will be restarted as long as the program exits and with an exit status of zero.
|
||||||
If false, the job will be restarted in the inverse condition. This key implies that "RunAtLoad"
|
If false, the job will be restarted in the inverse condition. This key implies that "RunAtLoad"
|
||||||
is set to true, since the job needs to run at least once before we can get an exit status.
|
is set to true, since the job needs to run at least once before we can get an exit status.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
NetworkState = mkOption {
|
NetworkState = mkOption {
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
If true, the job will be kept alive as long as the network is up, where up is defined as at least
|
If true, the job will be kept alive as long as the network is up, where up is defined as at least
|
||||||
one non-loopback interface being up and having IPv4 or IPv6 addresses assigned to them. If
|
one non-loopback interface being up and having IPv4 or IPv6 addresses assigned to them. If
|
||||||
false, the job will be kept alive in the inverse condition.
|
false, the job will be kept alive in the inverse condition.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
PathState = mkOption {
|
PathState = mkOption {
|
||||||
type = types.nullOr (types.attrsOf types.bool);
|
type = types.nullOr (types.attrsOf types.bool);
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
Each key in this dictionary is a file-system path. If the value of the key is true, then the job
|
Each key in this dictionary is a file-system path. If the value of the key is true, then the job
|
||||||
will be kept alive as long as the path exists. If false, the job will be kept alive in the
|
will be kept alive as long as the path exists. If false, the job will be kept alive in the
|
||||||
inverse condition. The intent of this feature is that two or more jobs may create semaphores in
|
inverse condition. The intent of this feature is that two or more jobs may create semaphores in
|
||||||
the file-system namespace.
|
the file-system namespace.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
OtherJobEnabled = mkOption {
|
OtherJobEnabled = mkOption {
|
||||||
type = types.nullOr (types.attrsOf types.bool);
|
type = types.nullOr (types.attrsOf types.bool);
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
Each key in this dictionary is the label of another job. If the value of the key is true, then
|
Each key in this dictionary is the label of another job. If the value of the key is true, then
|
||||||
this job is kept alive as long as that other job is enabled. Otherwise, if the value is false,
|
this job is kept alive as long as that other job is enabled. Otherwise, if the value is false,
|
||||||
then this job is kept alive as long as the other job is disabled. This feature should not be
|
then this job is kept alive as long as the other job is disabled. This feature should not be
|
||||||
considered a substitute for the use of IPC.
|
considered a substitute for the use of IPC.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
Crashed = mkOption {
|
Crashed = mkOption {
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
If true, the the job will be restarted as long as it exited due to a signal which is typically
|
If true, the the job will be restarted as long as it exited due to a signal which is typically
|
||||||
associated with a crash (SIGILL, SIGSEGV, etc.). If false, the job will be restarted in the
|
associated with a crash (SIGILL, SIGSEGV, etc.). If false, the job will be restarted in the
|
||||||
inverse condition.
|
inverse condition.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
AfterInitialDemand = mkOption {
|
AfterInitialDemand = mkOption {
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}));
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
This optional key is used to control whether your job is to be kept continuously running or to let
|
This optional key is used to control whether your job is to be kept continuously running or to let
|
||||||
|
|
@ -371,10 +385,12 @@ in {
|
||||||
|
|
||||||
StartCalendarInterval = mkOption {
|
StartCalendarInterval = mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
example = [{
|
example = [
|
||||||
Hour = 2;
|
{
|
||||||
Minute = 30;
|
Hour = 2;
|
||||||
}];
|
Minute = 30;
|
||||||
|
}
|
||||||
|
];
|
||||||
description = ''
|
description = ''
|
||||||
This optional key causes the job to be started every calendar interval as specified. The semantics are
|
This optional key causes the job to be started every calendar interval as specified. The semantics are
|
||||||
much like {manpage}`crontab(5)`: Missing attributes are considered to be wildcard. Unlike cron which skips
|
much like {manpage}`crontab(5)`: Missing attributes are considered to be wildcard. Unlike cron which skips
|
||||||
|
|
@ -442,181 +458,187 @@ in {
|
||||||
Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following
|
Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following
|
||||||
keys apply:
|
keys apply:
|
||||||
'';
|
'';
|
||||||
type = types.nullOr (types.submodule {
|
type = types.nullOr (
|
||||||
options = {
|
types.submodule {
|
||||||
Core = mkOption {
|
options = {
|
||||||
type = types.nullOr types.int;
|
Core = mkOption {
|
||||||
default = null;
|
type = types.nullOr types.int;
|
||||||
description = ''
|
default = null;
|
||||||
The largest size (in bytes) core file that may be created.
|
description = ''
|
||||||
'';
|
The largest size (in bytes) core file that may be created.
|
||||||
};
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
CPU = mkOption {
|
CPU = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum amount of cpu time (in seconds) to be used by each process.
|
The maximum amount of cpu time (in seconds) to be used by each process.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
Data = mkOption {
|
Data = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum size (in bytes) of the data segment for a process; this defines how far a program may
|
The maximum size (in bytes) of the data segment for a process; this defines how far a program may
|
||||||
extend its break with the `sbrk(2)` system call.
|
extend its break with the `sbrk(2)` system call.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
FileSize = mkOption {
|
FileSize = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The largest size (in bytes) file that may be created.
|
The largest size (in bytes) file that may be created.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
MemoryLock = mkOption {
|
MemoryLock = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum size (in bytes) which a process may lock into memory using the mlock(2) function.
|
The maximum size (in bytes) which a process may lock into memory using the mlock(2) function.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
NumberOfFiles = mkOption {
|
NumberOfFiles = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum number of open files for this process. Setting this value in a system wide daemon
|
The maximum number of open files for this process. Setting this value in a system wide daemon
|
||||||
will set the `sysctl(3)` kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
|
will set the `sysctl(3)` kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
|
||||||
value in addition to the `setrlimit(2)` values.
|
value in addition to the `setrlimit(2)` values.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
NumberOfProcesses = mkOption {
|
NumberOfProcesses = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum number of simultaneous processes for this user id. Setting this value in a system
|
The maximum number of simultaneous processes for this user id. Setting this value in a system
|
||||||
wide daemon will set the `sysctl(3)` kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
|
wide daemon will set the `sysctl(3)` kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
|
||||||
(HardResourceLimits) value in addition to the `setrlimit(2)` values.
|
(HardResourceLimits) value in addition to the `setrlimit(2)` values.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
ResidentSetSize = mkOption {
|
ResidentSetSize = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum size (in bytes) to which a process's resident set size may grow. This imposes a
|
The maximum size (in bytes) to which a process's resident set size may grow. This imposes a
|
||||||
limit on the amount of physical memory to be given to a process; if memory is tight, the system
|
limit on the amount of physical memory to be given to a process; if memory is tight, the system
|
||||||
will prefer to take memory from processes that are exceeding their declared resident set size.
|
will prefer to take memory from processes that are exceeding their declared resident set size.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
Stack = mkOption {
|
Stack = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum size (in bytes) of the stack segment for a process; this defines how far a program's
|
The maximum size (in bytes) of the stack segment for a process; this defines how far a program's
|
||||||
stack segment may be extended. Stack extension is performed automatically by the system.
|
stack segment may be extended. Stack extension is performed automatically by the system.
|
||||||
'';
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
});
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
HardResourceLimits = mkOption {
|
HardResourceLimits = mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
example = { NumberOfFiles = 4096; };
|
example = {
|
||||||
|
NumberOfFiles = 4096;
|
||||||
|
};
|
||||||
description = ''
|
description = ''
|
||||||
Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following
|
Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following
|
||||||
keys apply:
|
keys apply:
|
||||||
'';
|
'';
|
||||||
type = types.nullOr (types.submodule {
|
type = types.nullOr (
|
||||||
options = {
|
types.submodule {
|
||||||
Core = mkOption {
|
options = {
|
||||||
type = types.nullOr types.int;
|
Core = mkOption {
|
||||||
default = null;
|
type = types.nullOr types.int;
|
||||||
description = ''
|
default = null;
|
||||||
The largest size (in bytes) core file that may be created.
|
description = ''
|
||||||
'';
|
The largest size (in bytes) core file that may be created.
|
||||||
};
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
CPU = mkOption {
|
CPU = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum amount of cpu time (in seconds) to be used by each process.
|
The maximum amount of cpu time (in seconds) to be used by each process.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
Data = mkOption {
|
Data = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum size (in bytes) of the data segment for a process; this defines how far a program may
|
The maximum size (in bytes) of the data segment for a process; this defines how far a program may
|
||||||
extend its break with the `sbrk(2)` system call.
|
extend its break with the `sbrk(2)` system call.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
FileSize = mkOption {
|
FileSize = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The largest size (in bytes) file that may be created.
|
The largest size (in bytes) file that may be created.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
MemoryLock = mkOption {
|
MemoryLock = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum size (in bytes) which a process may lock into memory using the `mlock(2)` function.
|
The maximum size (in bytes) which a process may lock into memory using the `mlock(2)` function.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
NumberOfFiles = mkOption {
|
NumberOfFiles = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum number of open files for this process. Setting this value in a system wide daemon
|
The maximum number of open files for this process. Setting this value in a system wide daemon
|
||||||
will set the `sysctl(3)` kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
|
will set the `sysctl(3)` kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
|
||||||
value in addition to the `setrlimit(2)` values.
|
value in addition to the `setrlimit(2)` values.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
NumberOfProcesses = mkOption {
|
NumberOfProcesses = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum number of simultaneous processes for this user id. Setting this value in a system
|
The maximum number of simultaneous processes for this user id. Setting this value in a system
|
||||||
wide daemon will set the `sysctl(3)` kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
|
wide daemon will set the `sysctl(3)` kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
|
||||||
(HardResourceLimits) value in addition to the `setrlimit(2)` values.
|
(HardResourceLimits) value in addition to the `setrlimit(2)` values.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
ResidentSetSize = mkOption {
|
ResidentSetSize = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum size (in bytes) to which a process's resident set size may grow. This imposes a
|
The maximum size (in bytes) to which a process's resident set size may grow. This imposes a
|
||||||
limit on the amount of physical memory to be given to a process; if memory is tight, the system
|
limit on the amount of physical memory to be given to a process; if memory is tight, the system
|
||||||
will prefer to take memory from processes that are exceeding their declared resident set size.
|
will prefer to take memory from processes that are exceeding their declared resident set size.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
Stack = mkOption {
|
Stack = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
The maximum size (in bytes) of the stack segment for a process; this defines how far a program's
|
The maximum size (in bytes) of the stack segment for a process; this defines how far a program's
|
||||||
stack segment may be extended. Stack extension is performed automatically by the system.
|
stack segment may be extended. Stack extension is performed automatically by the system.
|
||||||
'';
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
});
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Nice = mkOption {
|
Nice = mkOption {
|
||||||
|
|
@ -628,8 +650,14 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
ProcessType = mkOption {
|
ProcessType = mkOption {
|
||||||
type = types.nullOr
|
type = types.nullOr (
|
||||||
(types.enum [ "Background" "Standard" "Adaptive" "Interactive" ]);
|
types.enum [
|
||||||
|
"Background"
|
||||||
|
"Standard"
|
||||||
|
"Adaptive"
|
||||||
|
"Interactive"
|
||||||
|
]
|
||||||
|
);
|
||||||
default = null;
|
default = null;
|
||||||
example = "Background";
|
example = "Background";
|
||||||
description = ''
|
description = ''
|
||||||
|
|
@ -694,7 +722,11 @@ in {
|
||||||
|
|
||||||
MachServices = mkOption {
|
MachServices = mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
example = { "org.nixos.service" = { ResetAtClose = true; }; };
|
example = {
|
||||||
|
"org.nixos.service" = {
|
||||||
|
ResetAtClose = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
description = ''
|
description = ''
|
||||||
This optional key is used to specify Mach services to be registered with the Mach bootstrap sub-system.
|
This optional key is used to specify Mach services to be registered with the Mach bootstrap sub-system.
|
||||||
Each key in this dictionary should be the name of service to be advertised. The value of the key must
|
Each key in this dictionary should be the name of service to be advertised. The value of the key must
|
||||||
|
|
@ -703,32 +735,37 @@ in {
|
||||||
Finally, for the job itself, the values will be replaced with Mach ports at the time of check-in with
|
Finally, for the job itself, the values will be replaced with Mach ports at the time of check-in with
|
||||||
launchd.
|
launchd.
|
||||||
'';
|
'';
|
||||||
type = types.nullOr (types.attrsOf (types.either types.bool
|
type = types.nullOr (
|
||||||
(types.submodule {
|
types.attrsOf (
|
||||||
options = {
|
types.either types.bool (
|
||||||
ResetAtClose = mkOption {
|
types.submodule {
|
||||||
type = types.nullOr types.bool;
|
options = {
|
||||||
default = null;
|
ResetAtClose = mkOption {
|
||||||
description = ''
|
type = types.nullOr types.bool;
|
||||||
If this boolean is false, the port is recycled, thus leaving clients to remain oblivious to the
|
default = null;
|
||||||
demand nature of job. If the value is set to true, clients receive port death notifications when
|
description = ''
|
||||||
the job lets go of the receive right. The port will be recreated atomically with respect to bootstrap_look_up()
|
If this boolean is false, the port is recycled, thus leaving clients to remain oblivious to the
|
||||||
calls, so that clients can trust that after receiving a port death notification,
|
demand nature of job. If the value is set to true, clients receive port death notifications when
|
||||||
the new port will have already been recreated. Setting the value to true should be done with
|
the job lets go of the receive right. The port will be recreated atomically with respect to bootstrap_look_up()
|
||||||
care. Not all clients may be able to handle this behavior. The default value is false.
|
calls, so that clients can trust that after receiving a port death notification,
|
||||||
'';
|
the new port will have already been recreated. Setting the value to true should be done with
|
||||||
};
|
care. Not all clients may be able to handle this behavior. The default value is false.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
HideUntilCheckIn = mkOption {
|
HideUntilCheckIn = mkOption {
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
Reserve the name in the namespace, but cause bootstrap_look_up() to fail until the job has
|
Reserve the name in the namespace, but cause bootstrap_look_up() to fail until the job has
|
||||||
checked in with launchd.
|
checked in with launchd.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
})));
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
LaunchEvents = mkOption {
|
LaunchEvents = mkOption {
|
||||||
|
|
@ -790,109 +827,123 @@ in {
|
||||||
|
|
||||||
The parameters below are used as inputs to call `getaddrinfo(3)`.
|
The parameters below are used as inputs to call `getaddrinfo(3)`.
|
||||||
'';
|
'';
|
||||||
type = types.nullOr (types.attrsOf (types.submodule {
|
type = types.nullOr (
|
||||||
options = {
|
types.attrsOf (
|
||||||
SockType = mkOption {
|
types.submodule {
|
||||||
type = types.nullOr (types.enum [ "stream" "dgram" "seqpacket" ]);
|
options = {
|
||||||
default = null;
|
SockType = mkOption {
|
||||||
description = ''
|
type = types.nullOr (
|
||||||
This optional key tells launchctl what type of socket to create. The default is "stream" and
|
types.enum [
|
||||||
other valid values for this key are "dgram" and "seqpacket" respectively.
|
"stream"
|
||||||
'';
|
"dgram"
|
||||||
};
|
"seqpacket"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
This optional key tells launchctl what type of socket to create. The default is "stream" and
|
||||||
|
other valid values for this key are "dgram" and "seqpacket" respectively.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
SockPassive = mkOption {
|
SockPassive = mkOption {
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
This optional key specifies whether `listen(2)` or `connect(2)` should be called on the created file
|
This optional key specifies whether `listen(2)` or `connect(2)` should be called on the created file
|
||||||
descriptor. The default is true ("to listen").
|
descriptor. The default is true ("to listen").
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
SockNodeName = mkOption {
|
SockNodeName = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
This optional key specifies the node to `connect(2)` or `bind(2)` to.
|
This optional key specifies the node to `connect(2)` or `bind(2)` to.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
SockServiceName = mkOption {
|
SockServiceName = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
This optional key specifies the service on the node to `connect(2)` or `bind(2)` to.
|
This optional key specifies the service on the node to `connect(2)` or `bind(2)` to.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
SockFamily = mkOption {
|
SockFamily = mkOption {
|
||||||
type = types.nullOr (types.enum [ "IPv4" "IPv6" ]);
|
type = types.nullOr (
|
||||||
default = null;
|
types.enum [
|
||||||
description = ''
|
"IPv4"
|
||||||
This optional key can be used to specifically request that "IPv4" or "IPv6" socket(s) be created.
|
"IPv6"
|
||||||
'';
|
]
|
||||||
};
|
);
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
This optional key can be used to specifically request that "IPv4" or "IPv6" socket(s) be created.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
SockProtocol = mkOption {
|
SockProtocol = mkOption {
|
||||||
type = types.nullOr (types.enum [ "TCP" ]);
|
type = types.nullOr (types.enum [ "TCP" ]);
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
This optional key specifies the protocol to be passed to `socket(2)`. The only value understood by
|
This optional key specifies the protocol to be passed to `socket(2)`. The only value understood by
|
||||||
this key at the moment is "TCP".
|
this key at the moment is "TCP".
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
SockPathName = mkOption {
|
SockPathName = mkOption {
|
||||||
type = types.nullOr types.path;
|
type = types.nullOr types.path;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
This optional key implies SockFamily is set to "Unix". It specifies the path to `connect(2)` or
|
This optional key implies SockFamily is set to "Unix". It specifies the path to `connect(2)` or
|
||||||
`bind(2)` to.
|
`bind(2)` to.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
SecureSocketWithKey = mkOption {
|
SecureSocketWithKey = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
This optional key is a variant of SockPathName. Instead of binding to a known path, a securely
|
This optional key is a variant of SockPathName. Instead of binding to a known path, a securely
|
||||||
generated socket is created and the path is assigned to the environment variable that is inherited
|
generated socket is created and the path is assigned to the environment variable that is inherited
|
||||||
by all jobs spawned by launchd.
|
by all jobs spawned by launchd.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
SockPathMode = mkOption {
|
SockPathMode = mkOption {
|
||||||
type = types.nullOr types.int;
|
type = types.nullOr types.int;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
This optional key specifies the mode of the socket. Known bug: Property lists don't support
|
This optional key specifies the mode of the socket. Known bug: Property lists don't support
|
||||||
octal, so please convert the value to decimal.
|
octal, so please convert the value to decimal.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
Bonjour = mkOption {
|
Bonjour = mkOption {
|
||||||
type =
|
type = types.nullOr (types.either types.bool (types.listOf types.str));
|
||||||
types.nullOr (types.either types.bool (types.listOf types.str));
|
default = null;
|
||||||
default = null;
|
description = ''
|
||||||
description = ''
|
This optional key can be used to request that the service be registered with the
|
||||||
This optional key can be used to request that the service be registered with the
|
`mDNSResponder(8)`. If the value is boolean, the service name is inferred from the SockServiceName.
|
||||||
`mDNSResponder(8)`. If the value is boolean, the service name is inferred from the SockServiceName.
|
'';
|
||||||
'';
|
};
|
||||||
};
|
|
||||||
|
|
||||||
MulticastGroup = mkOption {
|
MulticastGroup = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
This optional key can be used to request that the datagram socket join a multicast group. If the
|
This optional key can be used to request that the datagram socket join a multicast group. If the
|
||||||
value is a hostname, then `getaddrinfo(3)` will be used to join the correct multicast address for a
|
value is a hostname, then `getaddrinfo(3)` will be used to join the correct multicast address for a
|
||||||
given socket family. If an explicit IPv4 or IPv6 address is given, it is required that the SockFamily
|
given socket family. If an explicit IPv4 or IPv6 address is given, it is required that the SockFamily
|
||||||
family also be set, otherwise the results are undefined.
|
family also be set, otherwise the results are undefined.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}));
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,117 +5,146 @@
|
||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) imap1 types mkOption showOption mergeDefinitions;
|
inherit (lib)
|
||||||
inherit (builtins) map filter length deepSeq throw toString concatLists;
|
imap1
|
||||||
|
types
|
||||||
|
mkOption
|
||||||
|
showOption
|
||||||
|
mergeDefinitions
|
||||||
|
;
|
||||||
|
inherit (builtins)
|
||||||
|
map
|
||||||
|
filter
|
||||||
|
length
|
||||||
|
deepSeq
|
||||||
|
throw
|
||||||
|
toString
|
||||||
|
concatLists
|
||||||
|
;
|
||||||
inherit (lib.options) showDefs;
|
inherit (lib.options) showDefs;
|
||||||
wildcardText = lib.literalMD "`*`";
|
wildcardText = lib.literalMD "`*`";
|
||||||
|
|
||||||
/* *
|
/*
|
||||||
A type of list which does not allow duplicate elements. The base/inner
|
*
|
||||||
list type to use (e.g. `types.listOf` or `types.nonEmptyListOf`) is passed
|
A type of list which does not allow duplicate elements. The base/inner
|
||||||
via argument `listType`, which must be the final type and not a function.
|
list type to use (e.g. `types.listOf` or `types.nonEmptyListOf`) is passed
|
||||||
|
via argument `listType`, which must be the final type and not a function.
|
||||||
|
|
||||||
NOTE: The extra check for duplicates is quadratic and strict, so use this
|
NOTE: The extra check for duplicates is quadratic and strict, so use this
|
||||||
type sparingly and only:
|
type sparingly and only:
|
||||||
|
|
||||||
* when needed, and
|
* when needed, and
|
||||||
* when the list is expected to be recursively short (e.g. < 10 elements)
|
* when the list is expected to be recursively short (e.g. < 10 elements)
|
||||||
and shallow (i.e. strict evaluation of the list won't take too long)
|
and shallow (i.e. strict evaluation of the list won't take too long)
|
||||||
|
|
||||||
The implementation of this function is similar to that of
|
The implementation of this function is similar to that of
|
||||||
`types.nonEmptyListOf`.
|
`types.nonEmptyListOf`.
|
||||||
*/
|
*/
|
||||||
types'.uniqueList = listType:
|
types'.uniqueList =
|
||||||
listType // {
|
listType:
|
||||||
description = "unique ${
|
listType
|
||||||
types.optionDescriptionPhrase (class: class == "noun") listType
|
// {
|
||||||
}";
|
description = "unique ${types.optionDescriptionPhrase (class: class == "noun") listType}";
|
||||||
substSubModules = m: types'.uniqueList (listType.substSubModules m);
|
substSubModules = m: types'.uniqueList (listType.substSubModules m);
|
||||||
# This has been taken from the implementation of `types.listOf`, but has
|
# This has been taken from the implementation of `types.listOf`, but has
|
||||||
# been modified to throw on duplicates. This check cannot be done in the
|
# been modified to throw on duplicates. This check cannot be done in the
|
||||||
# `check` fn as this check is deep/strict, and because `check` runs
|
# `check` fn as this check is deep/strict, and because `check` runs
|
||||||
# prior to merging.
|
# prior to merging.
|
||||||
merge = loc: defs:
|
merge =
|
||||||
|
loc: defs:
|
||||||
let
|
let
|
||||||
# Each element of `dupes` is a list. When there are duplicates,
|
# Each element of `dupes` is a list. When there are duplicates,
|
||||||
# later lists will be duplicates of earlier lists, so just throw on
|
# later lists will be duplicates of earlier lists, so just throw on
|
||||||
# the first set of duplicates found so that we don't have duplicate
|
# the first set of duplicates found so that we don't have duplicate
|
||||||
# error msgs.
|
# error msgs.
|
||||||
checked = filter (li:
|
checked = filter (
|
||||||
|
li:
|
||||||
if length li > 1 then
|
if length li > 1 then
|
||||||
throw ''
|
throw ''
|
||||||
The option `${
|
The option `${showOption loc}' contains duplicate entries after merging:
|
||||||
showOption loc
|
|
||||||
}' contains duplicate entries after merging:
|
|
||||||
${showDefs li}''
|
${showDefs li}''
|
||||||
else
|
else
|
||||||
false) dupes;
|
false
|
||||||
dupes =
|
) dupes;
|
||||||
map (def: filter (def': def'.value == def.value) merged) merged;
|
dupes = map (def: filter (def': def'.value == def.value) merged) merged;
|
||||||
merged = filter (x: x ? value) (concatLists (imap1 (n: def:
|
merged = filter (x: x ? value) (
|
||||||
imap1 (m: el:
|
concatLists (
|
||||||
let
|
imap1 (
|
||||||
inherit (def) file;
|
n: def:
|
||||||
loc' = loc
|
imap1 (
|
||||||
++ [ "[definition ${toString n}-entry ${toString m}]" ];
|
m: el:
|
||||||
in (mergeDefinitions loc' listType.nestedTypes.elemType [{
|
let
|
||||||
inherit file;
|
inherit (def) file;
|
||||||
value = el;
|
loc' = loc ++ [ "[definition ${toString n}-entry ${toString m}]" ];
|
||||||
}]).optionalValue // {
|
in
|
||||||
inherit loc' file;
|
(mergeDefinitions loc' listType.nestedTypes.elemType [
|
||||||
}) def.value) defs));
|
{
|
||||||
in deepSeq checked (map (x: x.value) merged);
|
inherit file;
|
||||||
|
value = el;
|
||||||
|
}
|
||||||
|
]).optionalValue
|
||||||
|
// {
|
||||||
|
inherit loc' file;
|
||||||
|
}
|
||||||
|
) def.value
|
||||||
|
) defs
|
||||||
|
)
|
||||||
|
);
|
||||||
|
in
|
||||||
|
deepSeq checked (map (x: x.value) merged);
|
||||||
};
|
};
|
||||||
in {
|
in
|
||||||
StartCalendarInterval = let
|
{
|
||||||
CalendarIntervalEntry = types.submodule {
|
StartCalendarInterval =
|
||||||
options = {
|
let
|
||||||
Minute = mkOption {
|
CalendarIntervalEntry = types.submodule {
|
||||||
type = types.nullOr (types.ints.between 0 59);
|
options = {
|
||||||
default = null;
|
Minute = mkOption {
|
||||||
defaultText = wildcardText;
|
type = types.nullOr (types.ints.between 0 59);
|
||||||
description = ''
|
default = null;
|
||||||
The minute on which this job will be run.
|
defaultText = wildcardText;
|
||||||
'';
|
description = ''
|
||||||
};
|
The minute on which this job will be run.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
Hour = mkOption {
|
Hour = mkOption {
|
||||||
type = types.nullOr (types.ints.between 0 23);
|
type = types.nullOr (types.ints.between 0 23);
|
||||||
default = null;
|
default = null;
|
||||||
defaultText = wildcardText;
|
defaultText = wildcardText;
|
||||||
description = ''
|
description = ''
|
||||||
The hour on which this job will be run.
|
The hour on which this job will be run.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
Day = mkOption {
|
Day = mkOption {
|
||||||
type = types.nullOr (types.ints.between 1 31);
|
type = types.nullOr (types.ints.between 1 31);
|
||||||
default = null;
|
default = null;
|
||||||
defaultText = wildcardText;
|
defaultText = wildcardText;
|
||||||
description = ''
|
description = ''
|
||||||
The day on which this job will be run.
|
The day on which this job will be run.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
Weekday = mkOption {
|
Weekday = mkOption {
|
||||||
type = types.nullOr (types.ints.between 0 7);
|
type = types.nullOr (types.ints.between 0 7);
|
||||||
default = null;
|
default = null;
|
||||||
defaultText = wildcardText;
|
defaultText = wildcardText;
|
||||||
description = ''
|
description = ''
|
||||||
The weekday on which this job will be run (0 and 7 are Sunday).
|
The weekday on which this job will be run (0 and 7 are Sunday).
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
Month = mkOption {
|
Month = mkOption {
|
||||||
type = types.nullOr (types.ints.between 1 12);
|
type = types.nullOr (types.ints.between 1 12);
|
||||||
default = null;
|
default = null;
|
||||||
defaultText = wildcardText;
|
defaultText = wildcardText;
|
||||||
description = ''
|
description = ''
|
||||||
The month on which this job will be run.
|
The month on which this job will be run.
|
||||||
'';
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
in
|
||||||
in types.either CalendarIntervalEntry
|
types.either CalendarIntervalEntry (types'.uniqueList (types.nonEmptyListOf CalendarIntervalEntry));
|
||||||
(types'.uniqueList (types.nonEmptyListOf CalendarIntervalEntry));
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,13 @@
|
||||||
{
|
{
|
||||||
assertPlatform = module: pkgs: platforms: {
|
assertPlatform = module: pkgs: platforms: {
|
||||||
assertion = lib.elem pkgs.stdenv.hostPlatform.system platforms;
|
assertion = lib.elem pkgs.stdenv.hostPlatform.system platforms;
|
||||||
message = let
|
message =
|
||||||
platformsStr = lib.concatStringsSep "\n"
|
let
|
||||||
(map (p: " - ${p}") (lib.sort (a: b: a < b) platforms));
|
platformsStr = lib.concatStringsSep "\n" (map (p: " - ${p}") (lib.sort (a: b: a < b) platforms));
|
||||||
in ''
|
in
|
||||||
The module ${module} does not support your platform. It only supports
|
''
|
||||||
|
The module ${module} does not support your platform. It only supports
|
||||||
|
|
||||||
${platformsStr}'';
|
${platformsStr}'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
{ lib }: {
|
{ lib }:
|
||||||
|
{
|
||||||
# Converts a boolean to a yes/no string. This is used in lots of
|
# Converts a boolean to a yes/no string. This is used in lots of
|
||||||
# configuration formats.
|
# configuration formats.
|
||||||
yesNo = value: if value then "yes" else "no";
|
yesNo = value: if value then "yes" else "no";
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,23 @@
|
||||||
|
|
||||||
{ lib }:
|
{ lib }:
|
||||||
|
|
||||||
let inherit (lib) all filterAttrs head hm mapAttrs length tail toposort;
|
let
|
||||||
in {
|
inherit (lib)
|
||||||
|
all
|
||||||
|
filterAttrs
|
||||||
|
head
|
||||||
|
hm
|
||||||
|
mapAttrs
|
||||||
|
length
|
||||||
|
tail
|
||||||
|
toposort
|
||||||
|
;
|
||||||
|
in
|
||||||
|
{
|
||||||
empty = { };
|
empty = { };
|
||||||
|
|
||||||
isEntry = e: e ? data && e ? after && e ? before;
|
isEntry = e: e ? data && e ? after && e ? before;
|
||||||
isDag = dag:
|
isDag = dag: builtins.isAttrs dag && all hm.dag.isEntry (builtins.attrValues dag);
|
||||||
builtins.isAttrs dag && all hm.dag.isEntry (builtins.attrValues dag);
|
|
||||||
|
|
||||||
# Takes an attribute set containing entries built by entryAnywhere,
|
# Takes an attribute set containing entries built by entryAnywhere,
|
||||||
# entryAfter, and entryBefore to a topologically sorted list of
|
# entryAfter, and entryBefore to a topologically sorted list of
|
||||||
|
|
@ -73,11 +83,10 @@ in {
|
||||||
# ];
|
# ];
|
||||||
# }
|
# }
|
||||||
# true
|
# true
|
||||||
topoSort = dag:
|
topoSort =
|
||||||
|
dag:
|
||||||
let
|
let
|
||||||
dagBefore = dag: name:
|
dagBefore = dag: name: builtins.attrNames (filterAttrs (n: v: builtins.elem name v.before) dag);
|
||||||
builtins.attrNames
|
|
||||||
(filterAttrs (n: v: builtins.elem name v.before) dag);
|
|
||||||
normalizedDag = mapAttrs (n: v: {
|
normalizedDag = mapAttrs (n: v: {
|
||||||
name = n;
|
name = n;
|
||||||
data = v.data;
|
data = v.data;
|
||||||
|
|
@ -85,9 +94,12 @@ in {
|
||||||
}) dag;
|
}) dag;
|
||||||
before = a: b: builtins.elem a.name b.after;
|
before = a: b: builtins.elem a.name b.after;
|
||||||
sorted = toposort before (builtins.attrValues normalizedDag);
|
sorted = toposort before (builtins.attrValues normalizedDag);
|
||||||
in if sorted ? result then {
|
in
|
||||||
result = map (v: { inherit (v) name data; }) sorted.result;
|
if sorted ? result then
|
||||||
} else
|
{
|
||||||
|
result = map (v: { inherit (v) name data; }) sorted.result;
|
||||||
|
}
|
||||||
|
else
|
||||||
sorted;
|
sorted;
|
||||||
|
|
||||||
# Applies a function to each element of the given DAG.
|
# Applies a function to each element of the given DAG.
|
||||||
|
|
@ -107,21 +119,28 @@ in {
|
||||||
#
|
#
|
||||||
# The entries as a whole can be given a relation to other DAG nodes. All
|
# The entries as a whole can be given a relation to other DAG nodes. All
|
||||||
# generated nodes are then placed before or after those dependencies.
|
# generated nodes are then placed before or after those dependencies.
|
||||||
entriesBetween = tag:
|
entriesBetween =
|
||||||
|
tag:
|
||||||
let
|
let
|
||||||
go = i: before: after: entries:
|
go =
|
||||||
|
i: before: after: entries:
|
||||||
let
|
let
|
||||||
name = "${tag}-${toString i}";
|
name = "${tag}-${toString i}";
|
||||||
i' = i + 1;
|
i' = i + 1;
|
||||||
in if entries == [ ] then
|
in
|
||||||
|
if entries == [ ] then
|
||||||
hm.dag.empty
|
hm.dag.empty
|
||||||
else if length entries == 1 then {
|
else if length entries == 1 then
|
||||||
"${name}" = hm.dag.entryBetween before after (head entries);
|
{
|
||||||
} else
|
"${name}" = hm.dag.entryBetween before after (head entries);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
"${name}" = hm.dag.entryAfter after (head entries);
|
"${name}" = hm.dag.entryAfter after (head entries);
|
||||||
} // go (i + 1) before [ name ] (tail entries);
|
}
|
||||||
in go 0;
|
// go (i + 1) before [ name ] (tail entries);
|
||||||
|
in
|
||||||
|
go 0;
|
||||||
|
|
||||||
entriesAnywhere = tag: hm.dag.entriesBetween tag [ ] [ ];
|
entriesAnywhere = tag: hm.dag.entriesBetween tag [ ] [ ];
|
||||||
entriesAfter = tag: hm.dag.entriesBetween tag [ ];
|
entriesAfter = tag: hm.dag.entriesBetween tag [ ];
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,22 @@
|
||||||
{ homeDirectory, lib, pkgs }:
|
{
|
||||||
|
homeDirectory,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
hasPrefix hm literalExpression mkDefault mkIf mkOption removePrefix types;
|
hasPrefix
|
||||||
in {
|
hm
|
||||||
|
literalExpression
|
||||||
|
mkDefault
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
removePrefix
|
||||||
|
types
|
||||||
|
;
|
||||||
|
in
|
||||||
|
{
|
||||||
# Constructs a type suitable for a `home.file` like option. The
|
# Constructs a type suitable for a `home.file` like option. The
|
||||||
# target path may be either absolute or relative, in which case it
|
# target path may be either absolute or relative, in which case it
|
||||||
# is relative the `basePath` argument (which itself must be an
|
# is relative the `basePath` argument (which itself must be an
|
||||||
|
|
@ -13,108 +26,121 @@ in {
|
||||||
# - opt the name of the option, for self-references
|
# - opt the name of the option, for self-references
|
||||||
# - basePathDesc docbook compatible description of the base path
|
# - basePathDesc docbook compatible description of the base path
|
||||||
# - basePath the file base path
|
# - basePath the file base path
|
||||||
fileType = opt: basePathDesc: basePath:
|
fileType =
|
||||||
types.attrsOf (types.submodule ({ name, config, ... }: {
|
opt: basePathDesc: basePath:
|
||||||
options = {
|
types.attrsOf (
|
||||||
enable = mkOption {
|
types.submodule (
|
||||||
type = types.bool;
|
{ name, config, ... }:
|
||||||
default = true;
|
{
|
||||||
description = ''
|
options = {
|
||||||
Whether this file should be generated. This option allows specific
|
enable = mkOption {
|
||||||
files to be disabled.
|
type = types.bool;
|
||||||
'';
|
default = true;
|
||||||
};
|
description = ''
|
||||||
target = mkOption {
|
Whether this file should be generated. This option allows specific
|
||||||
type = types.str;
|
files to be disabled.
|
||||||
apply = p:
|
'';
|
||||||
let absPath = if hasPrefix "/" p then p else "${basePath}/${p}";
|
};
|
||||||
in removePrefix (homeDirectory + "/") absPath;
|
target = mkOption {
|
||||||
defaultText = literalExpression "name";
|
type = types.str;
|
||||||
description = ''
|
apply =
|
||||||
Path to target file relative to ${basePathDesc}.
|
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}.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
text = mkOption {
|
text = mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
type = types.nullOr types.lines;
|
type = types.nullOr types.lines;
|
||||||
description = ''
|
description = ''
|
||||||
Text of the file. If this option is null then
|
Text of the file. If this option is null then
|
||||||
[](#opt-${opt}._name_.source)
|
[](#opt-${opt}._name_.source)
|
||||||
must be set.
|
must be set.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
source = mkOption {
|
source = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
description = ''
|
description = ''
|
||||||
Path of the source file or directory. If
|
Path of the source file or directory. If
|
||||||
[](#opt-${opt}._name_.text)
|
[](#opt-${opt}._name_.text)
|
||||||
is non-null then this option will automatically point to a file
|
is non-null then this option will automatically point to a file
|
||||||
containing that text.
|
containing that text.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
executable = mkOption {
|
executable = mkOption {
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
Set the execute bit. If `null`, defaults to the mode
|
Set the execute bit. If `null`, defaults to the mode
|
||||||
of the {var}`source` file or to `false`
|
of the {var}`source` file or to `false`
|
||||||
for files created through the {var}`text` option.
|
for files created through the {var}`text` option.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
recursive = mkOption {
|
recursive = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
If the file source is a directory, then this option
|
If the file source is a directory, then this option
|
||||||
determines whether the directory should be recursively
|
determines whether the directory should be recursively
|
||||||
linked to the target location. This option has no effect
|
linked to the target location. This option has no effect
|
||||||
if the source is a file.
|
if the source is a file.
|
||||||
|
|
||||||
If `false` (the default) then the target
|
If `false` (the default) then the target
|
||||||
will be a symbolic link to the source directory. If
|
will be a symbolic link to the source directory. If
|
||||||
`true` then the target will be a
|
`true` then the target will be a
|
||||||
directory structure matching the source's but whose leafs
|
directory structure matching the source's but whose leafs
|
||||||
are symbolic links to the files of the source directory.
|
are symbolic links to the files of the source directory.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
onChange = mkOption {
|
onChange = mkOption {
|
||||||
type = types.lines;
|
type = types.lines;
|
||||||
default = "";
|
default = "";
|
||||||
description = ''
|
description = ''
|
||||||
Shell commands to run when file has changed between
|
Shell commands to run when file has changed between
|
||||||
generations. The script will be run
|
generations. The script will be run
|
||||||
*after* the new files have been linked
|
*after* the new files have been linked
|
||||||
into place.
|
into place.
|
||||||
|
|
||||||
Note, this code is always run when `recursive` is
|
Note, this code is always run when `recursive` is
|
||||||
enabled.
|
enabled.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
force = mkOption {
|
force = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
Whether the target path should be unconditionally replaced
|
Whether the target path should be unconditionally replaced
|
||||||
by the managed file source. Warning, this will silently
|
by the managed file source. Warning, this will silently
|
||||||
delete the target regardless of whether it is a file or
|
delete the target regardless of whether it is a file or
|
||||||
link.
|
link.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
target = mkDefault name;
|
target = mkDefault name;
|
||||||
source = mkIf (config.text != null) (mkDefault (pkgs.writeTextFile {
|
source = mkIf (config.text != null) (
|
||||||
inherit (config) text;
|
mkDefault (
|
||||||
executable = config.executable == true; # can be null
|
pkgs.writeTextFile {
|
||||||
name = hm.strings.storeFileName name;
|
inherit (config) text;
|
||||||
}));
|
executable = config.executable == true; # can be null
|
||||||
};
|
name = hm.strings.storeFileName name;
|
||||||
}));
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,114 +1,158 @@
|
||||||
{ lib }:
|
{ lib }:
|
||||||
|
|
||||||
{
|
{
|
||||||
toHyprconf = { attrs, indentLevel ? 0, importantPrefixes ? [ "$" ], }:
|
toHyprconf =
|
||||||
|
{
|
||||||
|
attrs,
|
||||||
|
indentLevel ? 0,
|
||||||
|
importantPrefixes ? [ "$" ],
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
all concatMapStringsSep concatStrings concatStringsSep filterAttrs foldl
|
all
|
||||||
generators hasPrefix isAttrs isList mapAttrsToList replicate;
|
concatMapStringsSep
|
||||||
|
concatStrings
|
||||||
|
concatStringsSep
|
||||||
|
filterAttrs
|
||||||
|
foldl
|
||||||
|
generators
|
||||||
|
hasPrefix
|
||||||
|
isAttrs
|
||||||
|
isList
|
||||||
|
mapAttrsToList
|
||||||
|
replicate
|
||||||
|
;
|
||||||
|
|
||||||
initialIndent = concatStrings (replicate indentLevel " ");
|
initialIndent = concatStrings (replicate indentLevel " ");
|
||||||
|
|
||||||
toHyprconf' = indent: attrs:
|
toHyprconf' =
|
||||||
|
indent: attrs:
|
||||||
let
|
let
|
||||||
sections =
|
sections = filterAttrs (n: v: isAttrs v || (isList v && all isAttrs v)) attrs;
|
||||||
filterAttrs (n: v: isAttrs v || (isList v && all isAttrs v)) attrs;
|
|
||||||
|
|
||||||
mkSection = n: attrs:
|
mkSection =
|
||||||
|
n: attrs:
|
||||||
if lib.isList attrs then
|
if lib.isList attrs then
|
||||||
(concatMapStringsSep "\n" (a: mkSection n a) attrs)
|
(concatMapStringsSep "\n" (a: mkSection n a) attrs)
|
||||||
else ''
|
else
|
||||||
${indent}${n} {
|
''
|
||||||
${toHyprconf' " ${indent}" attrs}${indent}}
|
${indent}${n} {
|
||||||
'';
|
${toHyprconf' " ${indent}" attrs}${indent}}
|
||||||
|
'';
|
||||||
|
|
||||||
mkFields = generators.toKeyValue {
|
mkFields = generators.toKeyValue {
|
||||||
listsAsDuplicateKeys = true;
|
listsAsDuplicateKeys = true;
|
||||||
inherit indent;
|
inherit indent;
|
||||||
};
|
};
|
||||||
|
|
||||||
allFields =
|
allFields = filterAttrs (n: v: !(isAttrs v || (isList v && all isAttrs v))) attrs;
|
||||||
filterAttrs (n: v: !(isAttrs v || (isList v && all isAttrs v)))
|
|
||||||
attrs;
|
|
||||||
|
|
||||||
isImportantField = n: _:
|
isImportantField =
|
||||||
foldl (acc: prev: if hasPrefix prev n then true else acc) false
|
n: _: foldl (acc: prev: if hasPrefix prev n then true else acc) false importantPrefixes;
|
||||||
importantPrefixes;
|
|
||||||
|
|
||||||
importantFields = filterAttrs isImportantField allFields;
|
importantFields = filterAttrs isImportantField allFields;
|
||||||
|
|
||||||
fields = builtins.removeAttrs allFields
|
fields = builtins.removeAttrs allFields (mapAttrsToList (n: _: n) importantFields);
|
||||||
(mapAttrsToList (n: _: n) importantFields);
|
in
|
||||||
in mkFields importantFields
|
mkFields importantFields
|
||||||
+ concatStringsSep "\n" (mapAttrsToList mkSection sections)
|
+ concatStringsSep "\n" (mapAttrsToList mkSection sections)
|
||||||
+ mkFields fields;
|
+ mkFields fields;
|
||||||
in toHyprconf' initialIndent attrs;
|
in
|
||||||
|
toHyprconf' initialIndent attrs;
|
||||||
|
|
||||||
toKDL = { }:
|
toKDL =
|
||||||
|
{ }:
|
||||||
let
|
let
|
||||||
inherit (lib) concatStringsSep splitString mapAttrsToList any;
|
inherit (lib)
|
||||||
|
concatStringsSep
|
||||||
|
splitString
|
||||||
|
mapAttrsToList
|
||||||
|
any
|
||||||
|
;
|
||||||
inherit (builtins) typeOf replaceStrings elem;
|
inherit (builtins) typeOf replaceStrings elem;
|
||||||
|
|
||||||
# ListOf String -> String
|
# ListOf String -> String
|
||||||
indentStrings = let
|
indentStrings =
|
||||||
# Although the input of this function is a list of strings,
|
let
|
||||||
# the strings themselves *will* contain newlines, so you need
|
# Although the input of this function is a list of strings,
|
||||||
# to normalize the list by joining and resplitting them.
|
# the strings themselves *will* contain newlines, so you need
|
||||||
unlines = lib.splitString "\n";
|
# to normalize the list by joining and resplitting them.
|
||||||
lines = lib.concatStringsSep "\n";
|
unlines = lib.splitString "\n";
|
||||||
indentAll = lines: concatStringsSep "\n" (map (x: " " + x) lines);
|
lines = lib.concatStringsSep "\n";
|
||||||
in stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines));
|
indentAll = lines: concatStringsSep "\n" (map (x: " " + x) lines);
|
||||||
|
in
|
||||||
|
stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines));
|
||||||
|
|
||||||
# String -> String
|
# String -> String
|
||||||
sanitizeString = replaceStrings [ "\n" ''"'' ] [ "\\n" ''\"'' ];
|
sanitizeString = replaceStrings [ "\n" ''"'' ] [ "\\n" ''\"'' ];
|
||||||
|
|
||||||
# OneOf [Int Float String Bool Null] -> String
|
# OneOf [Int Float String Bool Null] -> String
|
||||||
literalValueToString = element:
|
literalValueToString =
|
||||||
|
element:
|
||||||
lib.throwIfNot
|
lib.throwIfNot
|
||||||
(elem (typeOf element) [ "int" "float" "string" "bool" "null" ])
|
(elem (typeOf element) [
|
||||||
"Cannot convert value of type ${typeOf element} to KDL literal."
|
"int"
|
||||||
(if typeOf element == "null" then
|
"float"
|
||||||
"null"
|
"string"
|
||||||
else if element == false then
|
"bool"
|
||||||
"false"
|
"null"
|
||||||
else if element == true then
|
])
|
||||||
"true"
|
"Cannot convert value of type ${typeOf element} to KDL literal."
|
||||||
else if typeOf element == "string" then
|
(
|
||||||
''"${sanitizeString element}"''
|
if typeOf element == "null" then
|
||||||
else
|
"null"
|
||||||
toString element);
|
else if element == false then
|
||||||
|
"false"
|
||||||
|
else if element == true then
|
||||||
|
"true"
|
||||||
|
else if typeOf element == "string" then
|
||||||
|
''"${sanitizeString element}"''
|
||||||
|
else
|
||||||
|
toString element
|
||||||
|
);
|
||||||
|
|
||||||
# Attrset Conversion
|
# Attrset Conversion
|
||||||
# String -> AttrsOf Anything -> String
|
# String -> AttrsOf Anything -> String
|
||||||
convertAttrsToKDL = name: attrs:
|
convertAttrsToKDL =
|
||||||
|
name: attrs:
|
||||||
let
|
let
|
||||||
optArgsString = lib.optionalString (attrs ? "_args")
|
optArgsString = lib.optionalString (attrs ? "_args") (
|
||||||
(lib.pipe attrs._args [
|
lib.pipe attrs._args [
|
||||||
(map literalValueToString)
|
(map literalValueToString)
|
||||||
(lib.concatStringsSep " ")
|
(lib.concatStringsSep " ")
|
||||||
(s: s + " ")
|
(s: s + " ")
|
||||||
]);
|
]
|
||||||
|
);
|
||||||
|
|
||||||
optPropsString = lib.optionalString (attrs ? "_props")
|
optPropsString = lib.optionalString (attrs ? "_props") (
|
||||||
(lib.pipe attrs._props [
|
lib.pipe attrs._props [
|
||||||
(lib.mapAttrsToList
|
(lib.mapAttrsToList (name: value: "${name}=${literalValueToString value}"))
|
||||||
(name: value: "${name}=${literalValueToString value}"))
|
|
||||||
(lib.concatStringsSep " ")
|
(lib.concatStringsSep " ")
|
||||||
(s: s + " ")
|
(s: s + " ")
|
||||||
]);
|
]
|
||||||
|
);
|
||||||
|
|
||||||
children =
|
children = lib.filterAttrs (
|
||||||
lib.filterAttrs (name: _: !(elem name [ "_args" "_props" ])) attrs;
|
name: _:
|
||||||
in ''
|
!(elem name [
|
||||||
|
"_args"
|
||||||
|
"_props"
|
||||||
|
])
|
||||||
|
) attrs;
|
||||||
|
in
|
||||||
|
''
|
||||||
${name} ${optArgsString}${optPropsString}{
|
${name} ${optArgsString}${optPropsString}{
|
||||||
${indentStrings (mapAttrsToList convertAttributeToKDL children)}
|
${indentStrings (mapAttrsToList convertAttributeToKDL children)}
|
||||||
}'';
|
}'';
|
||||||
|
|
||||||
# List Conversion
|
# List Conversion
|
||||||
# String -> ListOf (OneOf [Int Float String Bool Null]) -> String
|
# String -> ListOf (OneOf [Int Float String Bool Null]) -> String
|
||||||
convertListOfFlatAttrsToKDL = name: list:
|
convertListOfFlatAttrsToKDL =
|
||||||
let flatElements = map literalValueToString list;
|
name: list:
|
||||||
in "${name} ${concatStringsSep " " flatElements}";
|
let
|
||||||
|
flatElements = map literalValueToString list;
|
||||||
|
in
|
||||||
|
"${name} ${concatStringsSep " " flatElements}";
|
||||||
|
|
||||||
# String -> ListOf Anything -> String
|
# String -> ListOf Anything -> String
|
||||||
convertListOfNonFlatAttrsToKDL = name: list: ''
|
convertListOfNonFlatAttrsToKDL = name: list: ''
|
||||||
|
|
@ -117,18 +161,39 @@
|
||||||
}'';
|
}'';
|
||||||
|
|
||||||
# String -> ListOf Anything -> String
|
# String -> ListOf Anything -> String
|
||||||
convertListToKDL = name: list:
|
convertListToKDL =
|
||||||
let elementsAreFlat = !any (el: elem (typeOf el) [ "list" "set" ]) list;
|
name: list:
|
||||||
in if elementsAreFlat then
|
let
|
||||||
|
elementsAreFlat =
|
||||||
|
!any (
|
||||||
|
el:
|
||||||
|
elem (typeOf el) [
|
||||||
|
"list"
|
||||||
|
"set"
|
||||||
|
]
|
||||||
|
) list;
|
||||||
|
in
|
||||||
|
if elementsAreFlat then
|
||||||
convertListOfFlatAttrsToKDL name list
|
convertListOfFlatAttrsToKDL name list
|
||||||
else
|
else
|
||||||
convertListOfNonFlatAttrsToKDL name list;
|
convertListOfNonFlatAttrsToKDL name list;
|
||||||
|
|
||||||
# Combined Conversion
|
# Combined Conversion
|
||||||
# String -> Anything -> String
|
# String -> Anything -> String
|
||||||
convertAttributeToKDL = name: value:
|
convertAttributeToKDL =
|
||||||
let vType = typeOf value;
|
name: value:
|
||||||
in if elem vType [ "int" "float" "bool" "null" "string" ] then
|
let
|
||||||
|
vType = typeOf value;
|
||||||
|
in
|
||||||
|
if
|
||||||
|
elem vType [
|
||||||
|
"int"
|
||||||
|
"float"
|
||||||
|
"bool"
|
||||||
|
"null"
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
then
|
||||||
"${name} ${literalValueToString value}"
|
"${name} ${literalValueToString value}"
|
||||||
else if vType == "set" then
|
else if vType == "set" then
|
||||||
convertAttrsToKDL name value
|
convertAttrsToKDL name value
|
||||||
|
|
@ -139,99 +204,153 @@
|
||||||
Cannot convert type `(${typeOf value})` to KDL:
|
Cannot convert type `(${typeOf value})` to KDL:
|
||||||
${name} = ${toString value}
|
${name} = ${toString value}
|
||||||
'';
|
'';
|
||||||
in attrs: ''
|
in
|
||||||
|
attrs: ''
|
||||||
${concatStringsSep "\n" (mapAttrsToList convertAttributeToKDL attrs)}
|
${concatStringsSep "\n" (mapAttrsToList convertAttributeToKDL attrs)}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
toSCFG = { }:
|
toSCFG =
|
||||||
|
{ }:
|
||||||
let
|
let
|
||||||
inherit (lib) concatStringsSep mapAttrsToList any;
|
inherit (lib) concatStringsSep mapAttrsToList any;
|
||||||
inherit (builtins) typeOf replaceStrings elem;
|
inherit (builtins) typeOf replaceStrings elem;
|
||||||
|
|
||||||
# ListOf String -> String
|
# ListOf String -> String
|
||||||
indentStrings = let
|
indentStrings =
|
||||||
# Although the input of this function is a list of strings,
|
let
|
||||||
# the strings themselves *will* contain newlines, so you need
|
# Although the input of this function is a list of strings,
|
||||||
# to normalize the list by joining and resplitting them.
|
# the strings themselves *will* contain newlines, so you need
|
||||||
unlines = lib.splitString "\n";
|
# to normalize the list by joining and resplitting them.
|
||||||
lines = lib.concatStringsSep "\n";
|
unlines = lib.splitString "\n";
|
||||||
indentAll = lines: concatStringsSep "\n" (map (x: " " + x) lines);
|
lines = lib.concatStringsSep "\n";
|
||||||
in stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines));
|
indentAll = lines: concatStringsSep "\n" (map (x: " " + x) lines);
|
||||||
|
in
|
||||||
|
stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines));
|
||||||
|
|
||||||
# String -> Bool
|
# String -> Bool
|
||||||
specialChars = s:
|
specialChars =
|
||||||
any (char: elem char (reserved ++ [ " " "'" "{" "}" ]))
|
s:
|
||||||
(lib.stringToCharacters s);
|
any (
|
||||||
|
char:
|
||||||
|
elem char (
|
||||||
|
reserved
|
||||||
|
++ [
|
||||||
|
" "
|
||||||
|
"'"
|
||||||
|
"{"
|
||||||
|
"}"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
) (lib.stringToCharacters s);
|
||||||
|
|
||||||
# String -> String
|
# String -> String
|
||||||
sanitizeString =
|
sanitizeString = replaceStrings reserved [
|
||||||
replaceStrings reserved [ ''\"'' "\\\\" "\\r" "\\n" "\\t" ];
|
''\"''
|
||||||
|
"\\\\"
|
||||||
|
"\\r"
|
||||||
|
"\\n"
|
||||||
|
"\\t"
|
||||||
|
];
|
||||||
|
|
||||||
reserved = [ ''"'' "\\" "\r" "\n" " " ];
|
reserved = [
|
||||||
|
''"''
|
||||||
|
"\\"
|
||||||
|
"\r"
|
||||||
|
"\n"
|
||||||
|
" "
|
||||||
|
];
|
||||||
|
|
||||||
# OneOf [Int Float String Bool] -> String
|
# OneOf [Int Float String Bool] -> String
|
||||||
literalValueToString = element:
|
literalValueToString =
|
||||||
lib.throwIfNot (elem (typeOf element) [ "int" "float" "string" "bool" ])
|
element:
|
||||||
"Cannot convert value of type ${typeOf element} to SCFG literal."
|
lib.throwIfNot
|
||||||
(if element == false then
|
(elem (typeOf element) [
|
||||||
"false"
|
"int"
|
||||||
else if element == true then
|
"float"
|
||||||
"true"
|
"string"
|
||||||
else if typeOf element == "string" then
|
"bool"
|
||||||
if element == "" || specialChars element then
|
])
|
||||||
''"${sanitizeString element}"''
|
"Cannot convert value of type ${typeOf element} to SCFG literal."
|
||||||
else
|
(
|
||||||
element
|
if element == false then
|
||||||
else
|
"false"
|
||||||
toString element);
|
else if element == true then
|
||||||
|
"true"
|
||||||
|
else if typeOf element == "string" then
|
||||||
|
if element == "" || specialChars element then ''"${sanitizeString element}"'' else element
|
||||||
|
else
|
||||||
|
toString element
|
||||||
|
);
|
||||||
|
|
||||||
# Bool -> ListOf (OneOf [Int Float String Bool]) -> String
|
# Bool -> ListOf (OneOf [Int Float String Bool]) -> String
|
||||||
toOptParamsString = cond: list:
|
toOptParamsString =
|
||||||
lib.optionalString (cond) (lib.pipe list [
|
cond: list:
|
||||||
(map literalValueToString)
|
lib.optionalString (cond) (
|
||||||
(concatStringsSep " ")
|
lib.pipe list [
|
||||||
(s: " " + s)
|
(map literalValueToString)
|
||||||
]);
|
(concatStringsSep " ")
|
||||||
|
(s: " " + s)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
# Attrset Conversion
|
# Attrset Conversion
|
||||||
# String -> AttrsOf Anything -> String
|
# String -> AttrsOf Anything -> String
|
||||||
convertAttrsToSCFG = name: attrs:
|
convertAttrsToSCFG =
|
||||||
|
name: attrs:
|
||||||
let
|
let
|
||||||
optParamsString = toOptParamsString (attrs ? "_params") attrs._params;
|
optParamsString = toOptParamsString (attrs ? "_params") attrs._params;
|
||||||
in ''
|
in
|
||||||
|
''
|
||||||
${name}${optParamsString} {
|
${name}${optParamsString} {
|
||||||
${indentStrings (convertToAttrsSCFG' attrs)}
|
${indentStrings (convertToAttrsSCFG' attrs)}
|
||||||
}'';
|
}'';
|
||||||
|
|
||||||
# Attrset Conversion
|
# Attrset Conversion
|
||||||
# AttrsOf Anything -> ListOf String
|
# AttrsOf Anything -> ListOf String
|
||||||
convertToAttrsSCFG' = attrs:
|
convertToAttrsSCFG' =
|
||||||
mapAttrsToList convertAttributeToSCFG
|
attrs:
|
||||||
(lib.filterAttrs (name: val: !isNull val && name != "_params") attrs);
|
mapAttrsToList convertAttributeToSCFG (
|
||||||
|
lib.filterAttrs (name: val: !isNull val && name != "_params") attrs
|
||||||
|
);
|
||||||
|
|
||||||
# List Conversion
|
# List Conversion
|
||||||
# String -> ListOf (OneOf [Int Float String Bool]) -> String
|
# String -> ListOf (OneOf [Int Float String Bool]) -> String
|
||||||
convertListOfFlatAttrsToSCFG = name: list:
|
convertListOfFlatAttrsToSCFG =
|
||||||
let optParamsString = toOptParamsString (list != [ ]) list;
|
name: list:
|
||||||
in "${name}${optParamsString}";
|
let
|
||||||
|
optParamsString = toOptParamsString (list != [ ]) list;
|
||||||
|
in
|
||||||
|
"${name}${optParamsString}";
|
||||||
|
|
||||||
# Combined Conversion
|
# Combined Conversion
|
||||||
# String -> Anything -> String
|
# String -> Anything -> String
|
||||||
convertAttributeToSCFG = name: value:
|
convertAttributeToSCFG =
|
||||||
lib.throwIf (name == "") "Directive must not be empty"
|
name: value:
|
||||||
(let vType = typeOf value;
|
lib.throwIf (name == "") "Directive must not be empty" (
|
||||||
in if elem vType [ "int" "float" "bool" "string" ] then
|
let
|
||||||
"${name} ${literalValueToString value}"
|
vType = typeOf value;
|
||||||
else if vType == "set" then
|
in
|
||||||
convertAttrsToSCFG name value
|
if
|
||||||
else if vType == "list" then
|
elem vType [
|
||||||
convertListOfFlatAttrsToSCFG name value
|
"int"
|
||||||
else
|
"float"
|
||||||
throw ''
|
"bool"
|
||||||
Cannot convert type `(${typeOf value})` to SCFG:
|
"string"
|
||||||
${name} = ${toString value}
|
]
|
||||||
'');
|
then
|
||||||
in attrs:
|
"${name} ${literalValueToString value}"
|
||||||
|
else if vType == "set" then
|
||||||
|
convertAttrsToSCFG name value
|
||||||
|
else if vType == "list" then
|
||||||
|
convertListOfFlatAttrsToSCFG name value
|
||||||
|
else
|
||||||
|
throw ''
|
||||||
|
Cannot convert type `(${typeOf value})` to SCFG:
|
||||||
|
${name} = ${toString value}
|
||||||
|
''
|
||||||
|
);
|
||||||
|
in
|
||||||
|
attrs:
|
||||||
lib.optionalString (attrs != { }) ''
|
lib.optionalString (attrs != { }) ''
|
||||||
${concatStringsSep "\n" (convertToAttrsSCFG' attrs)}
|
${concatStringsSep "\n" (convertToAttrsSCFG' attrs)}
|
||||||
'';
|
'';
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,13 @@
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
concatMapStringsSep concatStrings escape hasPrefix head replaceStrings;
|
concatMapStringsSep
|
||||||
|
concatStrings
|
||||||
|
escape
|
||||||
|
hasPrefix
|
||||||
|
head
|
||||||
|
replaceStrings
|
||||||
|
;
|
||||||
|
|
||||||
mkPrimitive = t: v: {
|
mkPrimitive = t: v: {
|
||||||
_type = "gvariant";
|
_type = "gvariant";
|
||||||
|
|
@ -36,7 +42,8 @@ let
|
||||||
|
|
||||||
# Returns the GVariant type of a given Nix value. If no type can be
|
# Returns the GVariant type of a given Nix value. If no type can be
|
||||||
# found for the value then the empty string is returned.
|
# found for the value then the empty string is returned.
|
||||||
typeOf = v:
|
typeOf =
|
||||||
|
v:
|
||||||
with type;
|
with type;
|
||||||
if builtins.isBool v then
|
if builtins.isBool v then
|
||||||
boolean
|
boolean
|
||||||
|
|
@ -47,29 +54,27 @@ let
|
||||||
else if builtins.isString v then
|
else if builtins.isString v then
|
||||||
string
|
string
|
||||||
else if builtins.isList v then
|
else if builtins.isList v then
|
||||||
let elemType = elemTypeOf v;
|
let
|
||||||
in if elemType == "" then "" else arrayOf elemType
|
elemType = elemTypeOf v;
|
||||||
|
in
|
||||||
|
if elemType == "" then "" else arrayOf elemType
|
||||||
else if builtins.isAttrs v && v ? type then
|
else if builtins.isAttrs v && v ? type then
|
||||||
v.type
|
v.type
|
||||||
else
|
else
|
||||||
"";
|
"";
|
||||||
|
|
||||||
elemTypeOf = vs:
|
elemTypeOf = vs: if builtins.isList vs then if vs == [ ] then "" else typeOf (head vs) else "";
|
||||||
if builtins.isList vs then
|
|
||||||
if vs == [ ] then "" else typeOf (head vs)
|
|
||||||
else
|
|
||||||
"";
|
|
||||||
|
|
||||||
mkMaybe = elemType: elem:
|
mkMaybe =
|
||||||
mkPrimitive (type.maybeOf elemType) elem // {
|
elemType: elem:
|
||||||
__toString = self:
|
mkPrimitive (type.maybeOf elemType) elem
|
||||||
if self.value == null then
|
// {
|
||||||
"@${self.type} nothing"
|
__toString =
|
||||||
else
|
self: if self.value == null then "@${self.type} nothing" else "just ${toString self.value}";
|
||||||
"just ${toString self.value}";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
in rec {
|
in
|
||||||
|
rec {
|
||||||
|
|
||||||
inherit type typeOf;
|
inherit type typeOf;
|
||||||
|
|
||||||
|
|
@ -83,7 +88,8 @@ in rec {
|
||||||
# Returns the GVariant value that most closely matches the given Nix
|
# Returns the GVariant value that most closely matches the given Nix
|
||||||
# value. If no GVariant value can be found then `null` is returned.
|
# value. If no GVariant value can be found then `null` is returned.
|
||||||
|
|
||||||
mkValue = v:
|
mkValue =
|
||||||
|
v:
|
||||||
if builtins.isBool v then
|
if builtins.isBool v then
|
||||||
mkBoolean v
|
mkBoolean v
|
||||||
else if builtins.isInt v then
|
else if builtins.isInt v then
|
||||||
|
|
@ -99,55 +105,77 @@ in rec {
|
||||||
else
|
else
|
||||||
null;
|
null;
|
||||||
|
|
||||||
mkArray = elemType: elems:
|
mkArray =
|
||||||
mkPrimitive (type.arrayOf elemType) (map mkValue elems) // {
|
elemType: elems:
|
||||||
__toString = self:
|
mkPrimitive (type.arrayOf elemType) (map mkValue elems)
|
||||||
"@${self.type} [${concatMapStringsSep "," toString self.value}]";
|
// {
|
||||||
|
__toString = self: "@${self.type} [${concatMapStringsSep "," toString self.value}]";
|
||||||
};
|
};
|
||||||
|
|
||||||
mkEmptyArray = elemType: mkArray elemType [ ];
|
mkEmptyArray = elemType: mkArray elemType [ ];
|
||||||
|
|
||||||
mkVariant = elem:
|
mkVariant =
|
||||||
let gvarElem = mkValue elem;
|
elem:
|
||||||
in mkPrimitive type.variant gvarElem // {
|
let
|
||||||
|
gvarElem = mkValue elem;
|
||||||
|
in
|
||||||
|
mkPrimitive type.variant gvarElem
|
||||||
|
// {
|
||||||
__toString = self: "@${self.type} <${toString self.value}>";
|
__toString = self: "@${self.type} <${toString self.value}>";
|
||||||
};
|
};
|
||||||
|
|
||||||
mkDictionaryEntry = elems:
|
mkDictionaryEntry =
|
||||||
|
elems:
|
||||||
let
|
let
|
||||||
gvarElems = map mkValue elems;
|
gvarElems = map mkValue elems;
|
||||||
dictionaryType = type.dictionaryEntryOf (map (e: e.type) gvarElems);
|
dictionaryType = type.dictionaryEntryOf (map (e: e.type) gvarElems);
|
||||||
in mkPrimitive dictionaryType gvarElems // {
|
in
|
||||||
__toString = self:
|
mkPrimitive dictionaryType gvarElems
|
||||||
"@${self.type} {${concatMapStringsSep "," toString self.value}}";
|
// {
|
||||||
|
__toString = self: "@${self.type} {${concatMapStringsSep "," toString self.value}}";
|
||||||
};
|
};
|
||||||
|
|
||||||
mkNothing = elemType: mkMaybe elemType null;
|
mkNothing = elemType: mkMaybe elemType null;
|
||||||
|
|
||||||
mkJust = elem: let gvarElem = mkValue elem; in mkMaybe gvarElem.type gvarElem;
|
mkJust =
|
||||||
|
elem:
|
||||||
|
let
|
||||||
|
gvarElem = mkValue elem;
|
||||||
|
in
|
||||||
|
mkMaybe gvarElem.type gvarElem;
|
||||||
|
|
||||||
mkTuple = elems:
|
mkTuple =
|
||||||
|
elems:
|
||||||
let
|
let
|
||||||
gvarElems = map mkValue elems;
|
gvarElems = map mkValue elems;
|
||||||
tupleType = type.tupleOf (map (e: e.type) gvarElems);
|
tupleType = type.tupleOf (map (e: e.type) gvarElems);
|
||||||
in mkPrimitive tupleType gvarElems // {
|
in
|
||||||
__toString = self:
|
mkPrimitive tupleType gvarElems
|
||||||
"@${self.type} (${concatMapStringsSep "," toString self.value})";
|
// {
|
||||||
|
__toString = self: "@${self.type} (${concatMapStringsSep "," toString self.value})";
|
||||||
};
|
};
|
||||||
|
|
||||||
mkBoolean = v:
|
mkBoolean =
|
||||||
mkPrimitive type.boolean v // {
|
v:
|
||||||
|
mkPrimitive type.boolean v
|
||||||
|
// {
|
||||||
__toString = self: if self.value then "true" else "false";
|
__toString = self: if self.value then "true" else "false";
|
||||||
};
|
};
|
||||||
|
|
||||||
mkString = v:
|
mkString =
|
||||||
let sanitize = s: replaceStrings [ "\n" ] [ "\\n" ] (escape [ "'" "\\" ] s);
|
v:
|
||||||
in mkPrimitive type.string v // {
|
let
|
||||||
|
sanitize = s: replaceStrings [ "\n" ] [ "\\n" ] (escape [ "'" "\\" ] s);
|
||||||
|
in
|
||||||
|
mkPrimitive type.string v
|
||||||
|
// {
|
||||||
__toString = self: "'${sanitize self.value}'";
|
__toString = self: "'${sanitize self.value}'";
|
||||||
};
|
};
|
||||||
|
|
||||||
mkObjectpath = v:
|
mkObjectpath =
|
||||||
mkPrimitive type.string v // {
|
v:
|
||||||
|
mkPrimitive type.string v
|
||||||
|
// {
|
||||||
__toString = self: "objectpath '${escape [ "'" ] self.value}'";
|
__toString = self: "objectpath '${escape [ "'" ] self.value}'";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -157,8 +185,10 @@ in rec {
|
||||||
|
|
||||||
mkUint16 = mkPrimitive type.uint16;
|
mkUint16 = mkPrimitive type.uint16;
|
||||||
|
|
||||||
mkInt32 = v:
|
mkInt32 =
|
||||||
mkPrimitive type.int32 v // {
|
v:
|
||||||
|
mkPrimitive type.int32 v
|
||||||
|
// {
|
||||||
__toString = self: toString self.value;
|
__toString = self: toString self.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -168,8 +198,10 @@ in rec {
|
||||||
|
|
||||||
mkUint64 = mkPrimitive type.uint64;
|
mkUint64 = mkPrimitive type.uint64;
|
||||||
|
|
||||||
mkDouble = v:
|
mkDouble =
|
||||||
mkPrimitive type.double v // {
|
v:
|
||||||
|
mkPrimitive type.double v
|
||||||
|
// {
|
||||||
__toString = self: toString self.value;
|
__toString = self: toString self.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,10 +107,12 @@
|
||||||
github = "d-dervishi";
|
github = "d-dervishi";
|
||||||
githubId = 61125355;
|
githubId = 61125355;
|
||||||
name = "David Dervishi";
|
name = "David Dervishi";
|
||||||
keys = [{
|
keys = [
|
||||||
longKeyId = "rsa4096/0xB1C012F0E7697195";
|
{
|
||||||
fingerprint = "4C92 E3B0 21B5 5562 A1E0 CE3D B1C0 12F0 E769 7195";
|
longKeyId = "rsa4096/0xB1C012F0E7697195";
|
||||||
}];
|
fingerprint = "4C92 E3B0 21B5 5562 A1E0 CE3D B1C0 12F0 E769 7195";
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
Dines97 = {
|
Dines97 = {
|
||||||
name = "Denis Kaynar";
|
name = "Denis Kaynar";
|
||||||
|
|
@ -147,8 +149,7 @@
|
||||||
email = "yiheng.he@proton.me";
|
email = "yiheng.he@proton.me";
|
||||||
matrix = "@hey2022:matrix.org";
|
matrix = "@hey2022:matrix.org";
|
||||||
github = "hey2022";
|
github = "hey2022";
|
||||||
keys =
|
keys = [ { fingerprint = "128E 09C0 6F73 D678 6BB5 E551 5EA5 3C75 F7BE 3EDE"; } ];
|
||||||
[{ fingerprint = "128E 09C0 6F73 D678 6BB5 E551 5EA5 3C75 F7BE 3EDE"; }];
|
|
||||||
};
|
};
|
||||||
jack5079 = {
|
jack5079 = {
|
||||||
name = "Jack W.";
|
name = "Jack W.";
|
||||||
|
|
@ -167,10 +168,12 @@
|
||||||
name = "Jessica";
|
name = "Jessica";
|
||||||
email = "jess+nix@jessie.cafe";
|
email = "jess+nix@jessie.cafe";
|
||||||
githubId = 43591752;
|
githubId = 43591752;
|
||||||
keys = [{
|
keys = [
|
||||||
longkeyid = "rsa3072/0xBA3350686C918606";
|
{
|
||||||
fingerprint = "8092 3BD1 ECD0 E436 671D C8E9 BA33 5068 6C91 8606";
|
longkeyid = "rsa3072/0xBA3350686C918606";
|
||||||
}];
|
fingerprint = "8092 3BD1 ECD0 E436 671D C8E9 BA33 5068 6C91 8606";
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
jkarlson = {
|
jkarlson = {
|
||||||
email = "jekarlson@gmail.com";
|
email = "jekarlson@gmail.com";
|
||||||
|
|
@ -250,10 +253,12 @@
|
||||||
email = "kamadorueda@gmail.com";
|
email = "kamadorueda@gmail.com";
|
||||||
github = "kamadorueda";
|
github = "kamadorueda";
|
||||||
githubId = 47480384;
|
githubId = 47480384;
|
||||||
keys = [{
|
keys = [
|
||||||
longkeyid = "rsa4096/0x04D0CEAF916A9A40";
|
{
|
||||||
fingerprint = "2BE3 BAFD 793E A349 ED1F F00F 04D0 CEAF 916A 9A40";
|
longkeyid = "rsa4096/0x04D0CEAF916A9A40";
|
||||||
}];
|
fingerprint = "2BE3 BAFD 793E A349 ED1F F00F 04D0 CEAF 916A 9A40";
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
katexochen = {
|
katexochen = {
|
||||||
name = "Paul Meyer";
|
name = "Paul Meyer";
|
||||||
|
|
@ -339,20 +344,24 @@
|
||||||
email = "nick@hassan.host";
|
email = "nick@hassan.host";
|
||||||
github = "n-hass";
|
github = "n-hass";
|
||||||
githubId = 72363381;
|
githubId = 72363381;
|
||||||
keys = [{
|
keys = [
|
||||||
longkeyid = "rsa4096/0xFC95AB946A781EE7";
|
{
|
||||||
fingerprint = "FDEE 6116 DBA7 8840 7323 4466 A371 5973 2728 A6A6";
|
longkeyid = "rsa4096/0xFC95AB946A781EE7";
|
||||||
}];
|
fingerprint = "FDEE 6116 DBA7 8840 7323 4466 A371 5973 2728 A6A6";
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
seylerius = {
|
seylerius = {
|
||||||
email = "sable@seyleri.us";
|
email = "sable@seyleri.us";
|
||||||
name = "Sable Seyler";
|
name = "Sable Seyler";
|
||||||
github = "seylerius";
|
github = "seylerius";
|
||||||
githubId = 1145981;
|
githubId = 1145981;
|
||||||
keys = [{
|
keys = [
|
||||||
logkeyid = "rsa4096/0x68BF2EAE6D91CAFF";
|
{
|
||||||
fingerprint = "F0E0 0311 126A CD72 4392 25E6 68BF 2EAE 6D91 CAFF";
|
logkeyid = "rsa4096/0x68BF2EAE6D91CAFF";
|
||||||
}];
|
fingerprint = "F0E0 0311 126A CD72 4392 25E6 68BF 2EAE 6D91 CAFF";
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
silmarp = {
|
silmarp = {
|
||||||
name = "Silmar Pereira da Silva Junior";
|
name = "Silmar Pereira da Silva Junior";
|
||||||
|
|
@ -394,10 +403,12 @@
|
||||||
github = "msfjarvis";
|
github = "msfjarvis";
|
||||||
githubId = "13348378";
|
githubId = "13348378";
|
||||||
name = "Harsh Shandilya";
|
name = "Harsh Shandilya";
|
||||||
keys = [{
|
keys = [
|
||||||
longkeyid = "rsa4096/0xB7843F823355E9B9";
|
{
|
||||||
fingerprint = "8F87 050B 0F9C B841 1515 7399 B784 3F82 3355 E9B9";
|
longkeyid = "rsa4096/0xB7843F823355E9B9";
|
||||||
}];
|
fingerprint = "8F87 050B 0F9C B841 1515 7399 B784 3F82 3355 E9B9";
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
ambroisie = {
|
ambroisie = {
|
||||||
email = "bruno.home-manager@belanyi.fr";
|
email = "bruno.home-manager@belanyi.fr";
|
||||||
|
|
@ -571,10 +582,12 @@
|
||||||
email = "88944439+rcerc@users.noreply.github.com";
|
email = "88944439+rcerc@users.noreply.github.com";
|
||||||
github = "rcerc";
|
github = "rcerc";
|
||||||
githubId = 88944439;
|
githubId = 88944439;
|
||||||
keys = [{
|
keys = [
|
||||||
longkeyid = "ed25519/0x3F98EC7EC2B87ED1";
|
{
|
||||||
fingerprint = "D5D6 FD1F 0D9A 3284 FB9B C26D 3F98 EC7E C2B8 7ED1";
|
longkeyid = "ed25519/0x3F98EC7EC2B87ED1";
|
||||||
}];
|
fingerprint = "D5D6 FD1F 0D9A 3284 FB9B C26D 3F98 EC7E C2B8 7ED1";
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
mtoohey = {
|
mtoohey = {
|
||||||
name = "Matthew Toohey";
|
name = "Matthew Toohey";
|
||||||
|
|
@ -594,8 +607,7 @@
|
||||||
matrix = "@soywod:matrix.org";
|
matrix = "@soywod:matrix.org";
|
||||||
github = "soywod";
|
github = "soywod";
|
||||||
githubId = 10437171;
|
githubId = 10437171;
|
||||||
keys =
|
keys = [ { fingerprint = "75F0 AB7C FE01 D077 AEE6 CAFD 353E 4A18 EE0F AB72"; } ];
|
||||||
[{ fingerprint = "75F0 AB7C FE01 D077 AEE6 CAFD 353E 4A18 EE0F AB72"; }];
|
|
||||||
};
|
};
|
||||||
tensor5 = {
|
tensor5 = {
|
||||||
github = "tensor5";
|
github = "tensor5";
|
||||||
|
|
@ -615,8 +627,7 @@
|
||||||
github = "toastal";
|
github = "toastal";
|
||||||
githubId = 561087;
|
githubId = 561087;
|
||||||
name = "toastal";
|
name = "toastal";
|
||||||
keys =
|
keys = [ { fingerprint = "7944 74B7 D236 DAB9 C9EF E7F9 5CCE 6F14 66D4 7C9E"; } ];
|
||||||
[{ fingerprint = "7944 74B7 D236 DAB9 C9EF E7F9 5CCE 6F14 66D4 7C9E"; }];
|
|
||||||
};
|
};
|
||||||
tomodachi94 = {
|
tomodachi94 = {
|
||||||
email = "tomodachi94+nixpkgs@protonmail.com";
|
email = "tomodachi94+nixpkgs@protonmail.com";
|
||||||
|
|
@ -683,8 +694,7 @@
|
||||||
email = "git+nix@cleslie.uk";
|
email = "git+nix@cleslie.uk";
|
||||||
github = "callumio";
|
github = "callumio";
|
||||||
githubId = 16057677;
|
githubId = 16057677;
|
||||||
keys =
|
keys = [ { fingerprint = "BC82 4BB5 1656 D144 285E A0EC D382 C4AF EECE AA90"; } ];
|
||||||
[{ fingerprint = "BC82 4BB5 1656 D144 285E A0EC D382 C4AF EECE AA90"; }];
|
|
||||||
};
|
};
|
||||||
ALameLlama = {
|
ALameLlama = {
|
||||||
name = "Nicholas Ciechanowski";
|
name = "Nicholas Ciechanowski";
|
||||||
|
|
@ -703,10 +713,12 @@
|
||||||
email = "me@hpsaucii.dev";
|
email = "me@hpsaucii.dev";
|
||||||
github = "HPsaucii";
|
github = "HPsaucii";
|
||||||
githubId = 126502193;
|
githubId = 126502193;
|
||||||
keys = [{
|
keys = [
|
||||||
longkeyid = "rsa4096/0xEDB2C634166AE6AD";
|
{
|
||||||
fingerprint = "AD32 73D4 5E0E 9478 E826 543F EDB2 C634 166A E6AD";
|
longkeyid = "rsa4096/0xEDB2C634166AE6AD";
|
||||||
}];
|
fingerprint = "AD32 73D4 5E0E 9478 E826 543F EDB2 C634 166A E6AD";
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
folliehiyuki = {
|
folliehiyuki = {
|
||||||
name = "Hoang Nguyen";
|
name = "Hoang Nguyen";
|
||||||
|
|
|
||||||
|
|
@ -1,66 +1,85 @@
|
||||||
{ lib }: rec {
|
{ lib }:
|
||||||
|
rec {
|
||||||
mkNushellInline = expr: lib.setType "nushell-inline" { inherit expr; };
|
mkNushellInline = expr: lib.setType "nushell-inline" { inherit expr; };
|
||||||
|
|
||||||
isNushellInline = lib.isType "nushell-inline";
|
isNushellInline = lib.isType "nushell-inline";
|
||||||
|
|
||||||
toNushell = { indent ? "", multiline ? true, asBindings ? false, }@args:
|
toNushell =
|
||||||
|
{
|
||||||
|
indent ? "",
|
||||||
|
multiline ? true,
|
||||||
|
asBindings ? false,
|
||||||
|
}@args:
|
||||||
v:
|
v:
|
||||||
let
|
let
|
||||||
innerIndent = "${indent} ";
|
innerIndent = "${indent} ";
|
||||||
introSpace = if multiline then ''
|
introSpace =
|
||||||
|
if multiline then
|
||||||
|
''
|
||||||
|
|
||||||
${innerIndent}'' else
|
${innerIndent}''
|
||||||
" ";
|
else
|
||||||
outroSpace = if multiline then ''
|
" ";
|
||||||
|
outroSpace =
|
||||||
|
if multiline then
|
||||||
|
''
|
||||||
|
|
||||||
${indent}'' else
|
${indent}''
|
||||||
" ";
|
else
|
||||||
|
" ";
|
||||||
innerArgs = args // {
|
innerArgs = args // {
|
||||||
indent = if asBindings then indent else innerIndent;
|
indent = if asBindings then indent else innerIndent;
|
||||||
asBindings = false;
|
asBindings = false;
|
||||||
};
|
};
|
||||||
concatItems = lib.concatStringsSep introSpace;
|
concatItems = lib.concatStringsSep introSpace;
|
||||||
|
|
||||||
generatedBindings = assert lib.assertMsg (badVarNames == [ ])
|
generatedBindings =
|
||||||
"Bad Nushell variable names: ${
|
assert lib.assertMsg (badVarNames == [ ])
|
||||||
lib.generators.toPretty { } badVarNames
|
"Bad Nushell variable names: ${lib.generators.toPretty { } badVarNames}";
|
||||||
}";
|
lib.concatStrings (
|
||||||
lib.concatStrings (lib.mapAttrsToList (key: value: ''
|
lib.mapAttrsToList (key: value: ''
|
||||||
${indent}let ${key} = ${toNushell innerArgs value}
|
${indent}let ${key} = ${toNushell innerArgs value}
|
||||||
'') v);
|
'') v
|
||||||
|
);
|
||||||
|
|
||||||
isBadVarName = name:
|
isBadVarName =
|
||||||
|
name:
|
||||||
# Extracted from https://github.com/nushell/nushell/blob/ebc7b80c23f777f70c5053cca428226b3fe00d30/crates/nu-parser/src/parser.rs#L33
|
# Extracted from https://github.com/nushell/nushell/blob/ebc7b80c23f777f70c5053cca428226b3fe00d30/crates/nu-parser/src/parser.rs#L33
|
||||||
# Variables with numeric or even empty names are allowed. The only requisite is not containing any of the following characters
|
# Variables with numeric or even empty names are allowed. The only requisite is not containing any of the following characters
|
||||||
let invalidVariableCharacters = ".[({+-*^/=!<>&|";
|
let
|
||||||
in lib.match "^[$]?[^${lib.escapeRegex invalidVariableCharacters}]+$"
|
invalidVariableCharacters = ".[({+-*^/=!<>&|";
|
||||||
name == null;
|
in
|
||||||
|
lib.match "^[$]?[^${lib.escapeRegex invalidVariableCharacters}]+$" name == null;
|
||||||
badVarNames = lib.filter isBadVarName (builtins.attrNames v);
|
badVarNames = lib.filter isBadVarName (builtins.attrNames v);
|
||||||
in if asBindings then
|
in
|
||||||
|
if asBindings then
|
||||||
generatedBindings
|
generatedBindings
|
||||||
else if v == null then
|
else if v == null then
|
||||||
"null"
|
"null"
|
||||||
else if lib.isInt v || lib.isFloat v || lib.isString v || lib.isBool v then
|
else if lib.isInt v || lib.isFloat v || lib.isString v || lib.isBool v then
|
||||||
lib.strings.toJSON v
|
lib.strings.toJSON v
|
||||||
else if lib.isList v then
|
else if lib.isList v then
|
||||||
(if v == [ ] then
|
(
|
||||||
"[]"
|
if v == [ ] then
|
||||||
else
|
"[]"
|
||||||
"[${introSpace}${
|
else
|
||||||
concatItems (map (value: "${toNushell innerArgs value}") v)
|
"[${introSpace}${concatItems (map (value: "${toNushell innerArgs value}") v)}${outroSpace}]"
|
||||||
}${outroSpace}]")
|
)
|
||||||
else if lib.isAttrs v then
|
else if lib.isAttrs v then
|
||||||
(if isNushellInline v then
|
(
|
||||||
"(${v.expr})"
|
if isNushellInline v then
|
||||||
else if v == { } then
|
"(${v.expr})"
|
||||||
"{}"
|
else if v == { } then
|
||||||
else if lib.isDerivation v then
|
"{}"
|
||||||
toString v
|
else if lib.isDerivation v then
|
||||||
else
|
toString v
|
||||||
"{${introSpace}${
|
else
|
||||||
concatItems (lib.mapAttrsToList (key: value:
|
"{${introSpace}${
|
||||||
"${lib.strings.toJSON key}: ${toNushell innerArgs value}") v)
|
concatItems (
|
||||||
}${outroSpace}}")
|
lib.mapAttrsToList (key: value: "${lib.strings.toJSON key}: ${toNushell innerArgs value}") v
|
||||||
|
)
|
||||||
|
}${outroSpace}}"
|
||||||
|
)
|
||||||
else
|
else
|
||||||
abort "nushell.toNushell: type ${lib.typeOf v} is unsupported";
|
abort "nushell.toNushell: type ${lib.typeOf v} is unsupported";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,27 +2,35 @@
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
mkShellIntegrationOption = name:
|
mkShellIntegrationOption =
|
||||||
{ config, baseName ? name, extraDescription ? "" }:
|
name:
|
||||||
let attrName = "enable${baseName}Integration";
|
{
|
||||||
in lib.mkOption {
|
config,
|
||||||
|
baseName ? name,
|
||||||
|
extraDescription ? "",
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
attrName = "enable${baseName}Integration";
|
||||||
|
in
|
||||||
|
lib.mkOption {
|
||||||
default = config.home.shell.${attrName};
|
default = config.home.shell.${attrName};
|
||||||
defaultText = lib.literalMD "[](#opt-home.shell.${attrName})";
|
defaultText = lib.literalMD "[](#opt-home.shell.${attrName})";
|
||||||
example = false;
|
example = false;
|
||||||
description = "Whether to enable ${name} integration.${
|
description = "Whether to enable ${name} integration.${
|
||||||
lib.optionalString (extraDescription != "")
|
lib.optionalString (extraDescription != "") ("\n\n" + extraDescription)
|
||||||
("\n\n" + extraDescription)
|
}";
|
||||||
}";
|
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
in rec {
|
in
|
||||||
|
rec {
|
||||||
# Produces a Bourne shell like statement that prepend new values to
|
# Produces a Bourne shell like statement that prepend new values to
|
||||||
# an possibly existing variable, using sep(arator).
|
# an possibly existing variable, using sep(arator).
|
||||||
# Example:
|
# Example:
|
||||||
# prependToVar ":" "PATH" [ "$HOME/bin" "$HOME/.local/bin" ]
|
# prependToVar ":" "PATH" [ "$HOME/bin" "$HOME/.local/bin" ]
|
||||||
# => "$HOME/bin:$HOME/.local/bin:${PATH:+:}\$PATH"
|
# => "$HOME/bin:$HOME/.local/bin:${PATH:+:}\$PATH"
|
||||||
prependToVar = sep: n: v:
|
prependToVar =
|
||||||
|
sep: n: v:
|
||||||
"${lib.concatStringsSep sep v}\${${n}:+${sep}}\$${n}";
|
"${lib.concatStringsSep sep v}\${${n}:+${sep}}\$${n}";
|
||||||
|
|
||||||
# Produces a Bourne shell like variable export statement.
|
# Produces a Bourne shell like variable export statement.
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,15 @@
|
||||||
|
|
||||||
nixpkgsLib:
|
nixpkgsLib:
|
||||||
|
|
||||||
let mkHmLib = import ./.;
|
let
|
||||||
in nixpkgsLib.extend (self: super: {
|
mkHmLib = import ./.;
|
||||||
hm = mkHmLib { lib = self; };
|
in
|
||||||
|
nixpkgsLib.extend (
|
||||||
|
self: super: {
|
||||||
|
hm = mkHmLib { lib = self; };
|
||||||
|
|
||||||
# For forward compatibility.
|
# For forward compatibility.
|
||||||
literalExpression = super.literalExpression or super.literalExample;
|
literalExpression = super.literalExpression or super.literalExample;
|
||||||
literalDocBook = super.literalDocBook or super.literalExample;
|
literalDocBook = super.literalDocBook or super.literalExample;
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,39 @@
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
genList length lowerChars replaceStrings stringToCharacters upperChars;
|
genList
|
||||||
in {
|
length
|
||||||
|
lowerChars
|
||||||
|
replaceStrings
|
||||||
|
stringToCharacters
|
||||||
|
upperChars
|
||||||
|
;
|
||||||
|
in
|
||||||
|
{
|
||||||
# Figures out a valid Nix store name for the given path.
|
# Figures out a valid Nix store name for the given path.
|
||||||
storeFileName = path:
|
storeFileName =
|
||||||
|
path:
|
||||||
let
|
let
|
||||||
# All characters that are considered safe. Note "-" is not
|
# All characters that are considered safe. Note "-" is not
|
||||||
# included to avoid "-" followed by digit being interpreted as a
|
# included to avoid "-" followed by digit being interpreted as a
|
||||||
# version.
|
# version.
|
||||||
safeChars = [ "+" "." "_" "?" "=" ] ++ lowerChars ++ upperChars
|
safeChars =
|
||||||
|
[
|
||||||
|
"+"
|
||||||
|
"."
|
||||||
|
"_"
|
||||||
|
"?"
|
||||||
|
"="
|
||||||
|
]
|
||||||
|
++ lowerChars
|
||||||
|
++ upperChars
|
||||||
++ stringToCharacters "0123456789";
|
++ stringToCharacters "0123456789";
|
||||||
|
|
||||||
empties = l: genList (x: "") (length l);
|
empties = l: genList (x: "") (length l);
|
||||||
|
|
||||||
unsafeInName =
|
unsafeInName = stringToCharacters (replaceStrings safeChars (empties safeChars) path);
|
||||||
stringToCharacters (replaceStrings safeChars (empties safeChars) path);
|
|
||||||
|
|
||||||
safeName = replaceStrings unsafeInName (empties unsafeInName) path;
|
safeName = replaceStrings unsafeInName (empties unsafeInName) path;
|
||||||
in "hm_" + safeName;
|
in
|
||||||
|
"hm_" + safeName;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,42 +2,65 @@
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
concatStringsSep defaultFunctor fixedWidthNumber hm imap1 isAttrs isList
|
concatStringsSep
|
||||||
length listToAttrs mapAttrs mkIf mkOrder mkOption mkOptionType nameValuePair
|
defaultFunctor
|
||||||
stringLength types warn;
|
fixedWidthNumber
|
||||||
|
hm
|
||||||
|
imap1
|
||||||
|
isAttrs
|
||||||
|
isList
|
||||||
|
length
|
||||||
|
listToAttrs
|
||||||
|
mapAttrs
|
||||||
|
mkIf
|
||||||
|
mkOrder
|
||||||
|
mkOption
|
||||||
|
mkOptionType
|
||||||
|
nameValuePair
|
||||||
|
stringLength
|
||||||
|
types
|
||||||
|
warn
|
||||||
|
;
|
||||||
|
|
||||||
dagEntryOf = elemType:
|
dagEntryOf =
|
||||||
|
elemType:
|
||||||
let
|
let
|
||||||
submoduleType = types.submodule ({ name, ... }: {
|
submoduleType = types.submodule (
|
||||||
options = {
|
{ name, ... }:
|
||||||
data = mkOption { type = elemType; };
|
{
|
||||||
after = mkOption { type = with types; listOf str; };
|
options = {
|
||||||
before = mkOption { type = with types; listOf str; };
|
data = mkOption { type = elemType; };
|
||||||
};
|
after = mkOption { type = with types; listOf str; };
|
||||||
config = mkIf (elemType.name == "submodule") {
|
before = mkOption { type = with types; listOf str; };
|
||||||
data._module.args.dagName = name;
|
};
|
||||||
};
|
config = mkIf (elemType.name == "submodule") {
|
||||||
});
|
data._module.args.dagName = name;
|
||||||
maybeConvert = def:
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
maybeConvert =
|
||||||
|
def:
|
||||||
if hm.dag.isEntry def.value then
|
if hm.dag.isEntry def.value then
|
||||||
def.value
|
def.value
|
||||||
else
|
else
|
||||||
hm.dag.entryAnywhere (if def ? priority then
|
hm.dag.entryAnywhere (if def ? priority then mkOrder def.priority def.value else def.value);
|
||||||
mkOrder def.priority def.value
|
in
|
||||||
else
|
mkOptionType {
|
||||||
def.value);
|
|
||||||
in mkOptionType {
|
|
||||||
name = "dagEntryOf";
|
name = "dagEntryOf";
|
||||||
description = "DAG entry of ${elemType.description}";
|
description = "DAG entry of ${elemType.description}";
|
||||||
# leave the checking to the submodule type
|
# leave the checking to the submodule type
|
||||||
merge = loc: defs:
|
merge =
|
||||||
submoduleType.merge loc (map (def: {
|
loc: defs:
|
||||||
inherit (def) file;
|
submoduleType.merge loc (
|
||||||
value = maybeConvert def;
|
map (def: {
|
||||||
}) defs);
|
inherit (def) file;
|
||||||
|
value = maybeConvert def;
|
||||||
|
}) defs
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
in rec {
|
in
|
||||||
|
rec {
|
||||||
# A directed acyclic graph of some inner type.
|
# A directed acyclic graph of some inner type.
|
||||||
#
|
#
|
||||||
# Note, if the element type is a submodule then the `name` argument
|
# Note, if the element type is a submodule then the `name` argument
|
||||||
|
|
@ -45,16 +68,21 @@ in rec {
|
||||||
# internal structure of the DAG values. To give access to the
|
# internal structure of the DAG values. To give access to the
|
||||||
# "actual" attribute name a new submodule argument is provided with
|
# "actual" attribute name a new submodule argument is provided with
|
||||||
# the name `dagName`.
|
# the name `dagName`.
|
||||||
dagOf = elemType:
|
dagOf =
|
||||||
let attrEquivalent = types.attrsOf (dagEntryOf elemType);
|
elemType:
|
||||||
in mkOptionType rec {
|
let
|
||||||
|
attrEquivalent = types.attrsOf (dagEntryOf elemType);
|
||||||
|
in
|
||||||
|
mkOptionType rec {
|
||||||
name = "dagOf";
|
name = "dagOf";
|
||||||
description = "DAG of ${elemType.description}";
|
description = "DAG of ${elemType.description}";
|
||||||
inherit (attrEquivalent) check merge emptyValue;
|
inherit (attrEquivalent) check merge emptyValue;
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "<name>" ]);
|
getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "<name>" ]);
|
||||||
getSubModules = elemType.getSubModules;
|
getSubModules = elemType.getSubModules;
|
||||||
substSubModules = m: dagOf (elemType.substSubModules m);
|
substSubModules = m: dagOf (elemType.substSubModules m);
|
||||||
functor = (defaultFunctor name) // { wrapped = elemType; };
|
functor = (defaultFunctor name) // {
|
||||||
|
wrapped = elemType;
|
||||||
|
};
|
||||||
nestedTypes.elemType = elemType;
|
nestedTypes.elemType = elemType;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,28 @@
|
||||||
{ lib, gvariant ? import ./gvariant.nix { inherit lib; } }:
|
{
|
||||||
|
lib,
|
||||||
|
gvariant ? import ./gvariant.nix { inherit lib; },
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
all concatMap foldl' getFiles getValues head isFunction literalExpression
|
all
|
||||||
mergeAttrs mergeDefaultOption mergeOneOption mergeOptions mkOption
|
concatMap
|
||||||
mkOptionType showFiles showOption types;
|
foldl'
|
||||||
|
getFiles
|
||||||
|
getValues
|
||||||
|
head
|
||||||
|
isFunction
|
||||||
|
literalExpression
|
||||||
|
mergeAttrs
|
||||||
|
mergeDefaultOption
|
||||||
|
mergeOneOption
|
||||||
|
mergeOptions
|
||||||
|
mkOption
|
||||||
|
mkOptionType
|
||||||
|
showFiles
|
||||||
|
showOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
typesDag = import ./types-dag.nix { inherit lib; };
|
typesDag = import ./types-dag.nix { inherit lib; };
|
||||||
|
|
||||||
|
|
@ -12,24 +30,30 @@ let
|
||||||
# must refer back to the type.
|
# must refer back to the type.
|
||||||
gvar = gvariant;
|
gvar = gvariant;
|
||||||
|
|
||||||
in rec {
|
in
|
||||||
|
rec {
|
||||||
|
|
||||||
inherit (typesDag) dagOf;
|
inherit (typesDag) dagOf;
|
||||||
|
|
||||||
selectorFunction = mkOptionType {
|
selectorFunction = mkOptionType {
|
||||||
name = "selectorFunction";
|
name = "selectorFunction";
|
||||||
description = "Function that takes an attribute set and returns a list"
|
description =
|
||||||
|
"Function that takes an attribute set and returns a list"
|
||||||
+ " containing a selection of the values of the input set";
|
+ " containing a selection of the values of the input set";
|
||||||
check = isFunction;
|
check = isFunction;
|
||||||
merge = _loc: defs: as: concatMap (select: select as) (getValues defs);
|
merge =
|
||||||
|
_loc: defs: as:
|
||||||
|
concatMap (select: select as) (getValues defs);
|
||||||
};
|
};
|
||||||
|
|
||||||
overlayFunction = mkOptionType {
|
overlayFunction = mkOptionType {
|
||||||
name = "overlayFunction";
|
name = "overlayFunction";
|
||||||
description = "An overlay function, takes self and super and returns"
|
description =
|
||||||
|
"An overlay function, takes self and super and returns"
|
||||||
+ " an attribute set overriding the desired attributes.";
|
+ " an attribute set overriding the desired attributes.";
|
||||||
check = isFunction;
|
check = isFunction;
|
||||||
merge = _loc: defs: self: super:
|
merge =
|
||||||
|
_loc: defs: self: super:
|
||||||
foldl' (res: def: mergeAttrs res (def.value self super)) { } defs;
|
foldl' (res: def: mergeAttrs res (def.value self super)) { } defs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -69,28 +93,34 @@ in rec {
|
||||||
name = "gvariant";
|
name = "gvariant";
|
||||||
description = "GVariant value";
|
description = "GVariant value";
|
||||||
check = v: gvar.mkValue v != null;
|
check = v: gvar.mkValue v != null;
|
||||||
merge = loc: defs:
|
merge =
|
||||||
|
loc: defs:
|
||||||
let
|
let
|
||||||
vdefs = map (d:
|
vdefs = map (
|
||||||
d // {
|
d:
|
||||||
value =
|
d
|
||||||
if gvar.isGVariant d.value then d.value else gvar.mkValue d.value;
|
// {
|
||||||
}) defs;
|
value = if gvar.isGVariant d.value then d.value else gvar.mkValue d.value;
|
||||||
|
}
|
||||||
|
) defs;
|
||||||
vals = map (d: d.value) vdefs;
|
vals = map (d: d.value) vdefs;
|
||||||
defTypes = map (x: x.type) vals;
|
defTypes = map (x: x.type) vals;
|
||||||
sameOrNull = x: y: if x == y then y else null;
|
sameOrNull = x: y: if x == y then y else null;
|
||||||
# A bit naive to just check the first entry…
|
# A bit naive to just check the first entry…
|
||||||
sharedDefType = foldl' sameOrNull (head defTypes) defTypes;
|
sharedDefType = foldl' sameOrNull (head defTypes) defTypes;
|
||||||
allChecked = all (x: check x) vals;
|
allChecked = all (x: check x) vals;
|
||||||
in if sharedDefType == null then
|
in
|
||||||
throw ("Cannot merge definitions of `${showOption loc}' with"
|
if sharedDefType == null then
|
||||||
|
throw (
|
||||||
|
"Cannot merge definitions of `${showOption loc}' with"
|
||||||
+ " mismatched GVariant types given in"
|
+ " mismatched GVariant types given in"
|
||||||
+ " ${showFiles (getFiles defs)}.")
|
+ " ${showFiles (getFiles defs)}."
|
||||||
|
)
|
||||||
else if gvar.isArray sharedDefType && allChecked then
|
else if gvar.isArray sharedDefType && allChecked then
|
||||||
gvar.mkValue ((types.listOf gvariant).merge loc
|
gvar.mkValue ((types.listOf gvariant).merge loc (map (d: d // { value = d.value.value; }) vdefs))
|
||||||
(map (d: d // { value = d.value.value; }) vdefs)) // {
|
// {
|
||||||
type = sharedDefType;
|
type = sharedDefType;
|
||||||
}
|
}
|
||||||
else if gvar.isTuple sharedDefType && allChecked then
|
else if gvar.isTuple sharedDefType && allChecked then
|
||||||
mergeOneOption loc defs
|
mergeOneOption loc defs
|
||||||
else if gvar.isMaybe sharedDefType && allChecked then
|
else if gvar.isMaybe sharedDefType && allChecked then
|
||||||
|
|
@ -107,27 +137,37 @@ in rec {
|
||||||
mergeDefaultOption loc defs;
|
mergeDefaultOption loc defs;
|
||||||
};
|
};
|
||||||
|
|
||||||
nushellValue = let
|
nushellValue =
|
||||||
valueType = types.nullOr (types.oneOf [
|
let
|
||||||
(lib.mkOptionType {
|
valueType = types.nullOr (
|
||||||
name = "nushell";
|
types.oneOf [
|
||||||
description = "Nushell inline value";
|
(lib.mkOptionType {
|
||||||
descriptionClass = "name";
|
name = "nushell";
|
||||||
check = lib.isType "nushell-inline";
|
description = "Nushell inline value";
|
||||||
})
|
descriptionClass = "name";
|
||||||
types.bool
|
check = lib.isType "nushell-inline";
|
||||||
types.int
|
})
|
||||||
types.float
|
types.bool
|
||||||
types.str
|
types.int
|
||||||
types.path
|
types.float
|
||||||
(types.attrsOf valueType // {
|
types.str
|
||||||
description = "attribute set of Nushell values";
|
types.path
|
||||||
descriptionClass = "name";
|
(
|
||||||
})
|
types.attrsOf valueType
|
||||||
(types.listOf valueType // {
|
// {
|
||||||
description = "list of Nushell values";
|
description = "attribute set of Nushell values";
|
||||||
descriptionClass = "name";
|
descriptionClass = "name";
|
||||||
})
|
}
|
||||||
]);
|
)
|
||||||
in valueType;
|
(
|
||||||
|
types.listOf valueType
|
||||||
|
// {
|
||||||
|
description = "list of Nushell values";
|
||||||
|
descriptionClass = "name";
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
in
|
||||||
|
valueType;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
rec {
|
rec {
|
||||||
# Produces a Zsh shell like value
|
# Produces a Zsh shell like value
|
||||||
toZshValue = v:
|
toZshValue =
|
||||||
|
v:
|
||||||
if builtins.isBool v then
|
if builtins.isBool v then
|
||||||
if v then "true" else "false"
|
if v then "true" else "false"
|
||||||
else if builtins.isString v then
|
else if builtins.isString v then
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
|
|
@ -9,7 +14,8 @@ let
|
||||||
inherit (config.home.version) release isReleaseBranch;
|
inherit (config.home.version) release isReleaseBranch;
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
manual.html.enable = lib.mkOption {
|
manual.html.enable = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
|
|
@ -51,7 +57,10 @@ in {
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
home.packages = lib.mkMerge [
|
home.packages = lib.mkMerge [
|
||||||
(lib.mkIf cfg.html.enable [ docs.manual.html docs.manual.htmlOpenTool ])
|
(lib.mkIf cfg.html.enable [
|
||||||
|
docs.manual.html
|
||||||
|
docs.manual.htmlOpenTool
|
||||||
|
])
|
||||||
(lib.mkIf cfg.manpages.enable [ docs.manPages ])
|
(lib.mkIf cfg.manpages.enable [ docs.manPages ])
|
||||||
(lib.mkIf cfg.json.enable [ docs.options.json ])
|
(lib.mkIf cfg.json.enable [ docs.options.json ])
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) types;
|
inherit (lib) types;
|
||||||
|
|
@ -7,18 +12,23 @@ let
|
||||||
|
|
||||||
toDconfIni = lib.generators.toINI { mkKeyValue = mkIniKeyValue; };
|
toDconfIni = lib.generators.toINI { mkKeyValue = mkIniKeyValue; };
|
||||||
|
|
||||||
mkIniKeyValue = key: value:
|
mkIniKeyValue = key: value: "${key}=${toString (lib.hm.gvariant.mkValue value)}";
|
||||||
"${key}=${toString (lib.hm.gvariant.mkValue value)}";
|
|
||||||
|
|
||||||
# The dconf keys managed by this configuration. We store this as part of the
|
# The dconf keys managed by this configuration. We store this as part of the
|
||||||
# generation state to be able to reset keys that become unmanaged during
|
# generation state to be able to reset keys that become unmanaged during
|
||||||
# switch.
|
# switch.
|
||||||
stateDconfKeys = pkgs.writeText "dconf-keys.json" (builtins.toJSON
|
stateDconfKeys = pkgs.writeText "dconf-keys.json" (
|
||||||
(lib.concatLists (lib.mapAttrsToList
|
builtins.toJSON (
|
||||||
(dir: entries: lib.mapAttrsToList (key: _: "/${dir}/${key}") entries)
|
lib.concatLists (
|
||||||
cfg.settings)));
|
lib.mapAttrsToList (
|
||||||
|
dir: entries: lib.mapAttrsToList (key: _: "/${dir}/${key}") entries
|
||||||
|
) cfg.settings
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.rycee ];
|
meta.maintainers = [ lib.maintainers.rycee ];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -84,8 +94,8 @@ in {
|
||||||
ln -s ${stateDconfKeys} $out/state/${stateDconfKeys.name}
|
ln -s ${stateDconfKeys} $out/state/${stateDconfKeys.name}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
home.activation.dconfSettings = lib.hm.dag.entryAfter [ "installPackages" ]
|
home.activation.dconfSettings = lib.hm.dag.entryAfter [ "installPackages" ] (
|
||||||
(let
|
let
|
||||||
iniFile = pkgs.writeText "hm-dconf.ini" (toDconfIni cfg.settings);
|
iniFile = pkgs.writeText "hm-dconf.ini" (toDconfIni cfg.settings);
|
||||||
|
|
||||||
statePath = "state/${stateDconfKeys.name}";
|
statePath = "state/${stateDconfKeys.name}";
|
||||||
|
|
@ -95,7 +105,12 @@ in {
|
||||||
|
|
||||||
${config.lib.bash.initHomeManagerLib}
|
${config.lib.bash.initHomeManagerLib}
|
||||||
|
|
||||||
PATH=${lib.makeBinPath [ pkgs.dconf pkgs.jq ]}''${PATH:+:}$PATH
|
PATH=${
|
||||||
|
lib.makeBinPath [
|
||||||
|
pkgs.dconf
|
||||||
|
pkgs.jq
|
||||||
|
]
|
||||||
|
}''${PATH:+:}$PATH
|
||||||
|
|
||||||
oldState="$1"
|
oldState="$1"
|
||||||
newState="$2"
|
newState="$2"
|
||||||
|
|
@ -116,7 +131,8 @@ in {
|
||||||
run $DCONF_DBUS_RUN_SESSION dconf reset "$key"
|
run $DCONF_DBUS_RUN_SESSION dconf reset "$key"
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
in ''
|
in
|
||||||
|
''
|
||||||
if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then
|
if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then
|
||||||
export DCONF_DBUS_RUN_SESSION=""
|
export DCONF_DBUS_RUN_SESSION=""
|
||||||
else
|
else
|
||||||
|
|
@ -132,6 +148,7 @@ in {
|
||||||
run $DCONF_DBUS_RUN_SESSION ${pkgs.dconf}/bin/dconf load / < ${iniFile}
|
run $DCONF_DBUS_RUN_SESSION ${pkgs.dconf}/bin/dconf load / < ${iniFile}
|
||||||
|
|
||||||
unset DCONF_DBUS_RUN_SESSION
|
unset DCONF_DBUS_RUN_SESSION
|
||||||
'');
|
''
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
|
|
@ -6,7 +11,8 @@ let
|
||||||
|
|
||||||
iniFormat = pkgs.formats.ini { };
|
iniFormat = pkgs.formats.ini { };
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = with lib.maintainers; [ loicreynier ];
|
meta.maintainers = with lib.maintainers; [ loicreynier ];
|
||||||
|
|
||||||
options.editorconfig = {
|
options.editorconfig = {
|
||||||
|
|
@ -38,14 +44,18 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf (cfg.enable && cfg.settings != { }) {
|
config = lib.mkIf (cfg.enable && cfg.settings != { }) {
|
||||||
home.file.".editorconfig".text = let
|
home.file.".editorconfig".text =
|
||||||
renderedSettings = lib.generators.toINIWithGlobalSection { } {
|
let
|
||||||
globalSection = { root = true; };
|
renderedSettings = lib.generators.toINIWithGlobalSection { } {
|
||||||
sections = cfg.settings;
|
globalSection = {
|
||||||
};
|
root = true;
|
||||||
in ''
|
};
|
||||||
# Generated by Home Manager
|
sections = cfg.settings;
|
||||||
${renderedSettings}
|
};
|
||||||
'';
|
in
|
||||||
|
''
|
||||||
|
# Generated by Home Manager
|
||||||
|
${renderedSettings}
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,12 @@
|
||||||
#
|
#
|
||||||
# https://github.com/NixOS/nixpkgs/blob/23.11/nixos/modules/config/fonts/fontconfig.nix
|
# https://github.com/NixOS/nixpkgs/blob/23.11/nixos/modules/config/fonts/fontconfig.nix
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
|
|
@ -10,15 +15,19 @@ let
|
||||||
|
|
||||||
profileDirectory = config.home.profileDirectory;
|
profileDirectory = config.home.profileDirectory;
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.rycee ];
|
meta.maintainers = [ lib.maintainers.rycee ];
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
(lib.mkRenamedOptionModule [ "fonts" "fontconfig" "enableProfileFonts" ] [
|
(lib.mkRenamedOptionModule
|
||||||
"fonts"
|
[ "fonts" "fontconfig" "enableProfileFonts" ]
|
||||||
"fontconfig"
|
[
|
||||||
"enable"
|
"fonts"
|
||||||
])
|
"fontconfig"
|
||||||
|
"enable"
|
||||||
|
]
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -117,53 +126,58 @@ in {
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
xdg.configFile = let
|
xdg.configFile =
|
||||||
mkFontconfigConf = conf: ''
|
let
|
||||||
<?xml version='1.0'?>
|
mkFontconfigConf = conf: ''
|
||||||
|
<?xml version='1.0'?>
|
||||||
|
|
||||||
<!-- Generated by Home Manager. -->
|
<!-- Generated by Home Manager. -->
|
||||||
|
|
||||||
<!DOCTYPE fontconfig SYSTEM 'urn:fontconfig:fonts.dtd'>
|
<!DOCTYPE fontconfig SYSTEM 'urn:fontconfig:fonts.dtd'>
|
||||||
<fontconfig>
|
<fontconfig>
|
||||||
${conf}
|
${conf}
|
||||||
</fontconfig>
|
</fontconfig>
|
||||||
'';
|
'';
|
||||||
in {
|
in
|
||||||
"fontconfig/conf.d/10-hm-fonts.conf".text = mkFontconfigConf ''
|
{
|
||||||
<description>Add fonts in the Nix user profile</description>
|
"fontconfig/conf.d/10-hm-fonts.conf".text = mkFontconfigConf ''
|
||||||
|
<description>Add fonts in the Nix user profile</description>
|
||||||
|
|
||||||
<include ignore_missing="yes">${config.home.path}/etc/fonts/conf.d</include>
|
<include ignore_missing="yes">${config.home.path}/etc/fonts/conf.d</include>
|
||||||
<include ignore_missing="yes">${config.home.path}/etc/fonts/fonts.conf</include>
|
<include ignore_missing="yes">${config.home.path}/etc/fonts/fonts.conf</include>
|
||||||
|
|
||||||
<dir>${config.home.path}/lib/X11/fonts</dir>
|
<dir>${config.home.path}/lib/X11/fonts</dir>
|
||||||
<dir>${config.home.path}/share/fonts</dir>
|
<dir>${config.home.path}/share/fonts</dir>
|
||||||
<dir>${profileDirectory}/lib/X11/fonts</dir>
|
<dir>${profileDirectory}/lib/X11/fonts</dir>
|
||||||
<dir>${profileDirectory}/share/fonts</dir>
|
<dir>${profileDirectory}/share/fonts</dir>
|
||||||
|
|
||||||
<cachedir>${config.home.path}/lib/fontconfig/cache</cachedir>
|
<cachedir>${config.home.path}/lib/fontconfig/cache</cachedir>
|
||||||
'';
|
'';
|
||||||
|
|
||||||
"fontconfig/conf.d/52-hm-default-fonts.conf".text = let
|
"fontconfig/conf.d/52-hm-default-fonts.conf".text =
|
||||||
genDefault = fonts: name:
|
let
|
||||||
lib.optionalString (fonts != [ ]) ''
|
genDefault =
|
||||||
<alias binding="same">
|
fonts: name:
|
||||||
<family>${name}</family>
|
lib.optionalString (fonts != [ ]) ''
|
||||||
<prefer>
|
<alias binding="same">
|
||||||
${
|
<family>${name}</family>
|
||||||
lib.concatStringsSep "" (map (font: ''
|
<prefer>
|
||||||
<family>${font}</family>
|
${lib.concatStringsSep "" (
|
||||||
'') fonts)
|
map (font: ''
|
||||||
}
|
<family>${font}</family>
|
||||||
</prefer>
|
'') fonts
|
||||||
</alias>
|
)}
|
||||||
|
</prefer>
|
||||||
|
</alias>
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
mkFontconfigConf ''
|
||||||
|
<!-- Default fonts -->
|
||||||
|
${genDefault cfg.defaultFonts.sansSerif "sans-serif"}
|
||||||
|
${genDefault cfg.defaultFonts.serif "serif"}
|
||||||
|
${genDefault cfg.defaultFonts.monospace "monospace"}
|
||||||
|
${genDefault cfg.defaultFonts.emoji "emoji"}
|
||||||
'';
|
'';
|
||||||
in mkFontconfigConf ''
|
};
|
||||||
<!-- Default fonts -->
|
|
||||||
${genDefault cfg.defaultFonts.sansSerif "sans-serif"}
|
|
||||||
${genDefault cfg.defaultFonts.serif "serif"}
|
|
||||||
${genDefault cfg.defaultFonts.monospace "monospace"}
|
|
||||||
${genDefault cfg.defaultFonts.emoji "emoji"}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) literalExpression mkOption optionalAttrs types;
|
inherit (lib)
|
||||||
|
literalExpression
|
||||||
|
mkOption
|
||||||
|
optionalAttrs
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.gtk;
|
cfg = config.gtk;
|
||||||
cfg2 = config.gtk.gtk2;
|
cfg2 = config.gtk.gtk2;
|
||||||
|
|
@ -9,22 +14,26 @@ let
|
||||||
cfg4 = config.gtk.gtk4;
|
cfg4 = config.gtk.gtk4;
|
||||||
|
|
||||||
toGtk3Ini = lib.generators.toINI {
|
toGtk3Ini = lib.generators.toINI {
|
||||||
mkKeyValue = key: value:
|
mkKeyValue =
|
||||||
|
key: value:
|
||||||
let
|
let
|
||||||
value' =
|
value' = if lib.isBool value then lib.boolToString value else toString value;
|
||||||
if lib.isBool value then lib.boolToString value else toString value;
|
in
|
||||||
in "${lib.escape [ "=" ] key}=${value'}";
|
"${lib.escape [ "=" ] key}=${value'}";
|
||||||
};
|
};
|
||||||
|
|
||||||
formatGtk2Option = n: v:
|
formatGtk2Option =
|
||||||
|
n: v:
|
||||||
let
|
let
|
||||||
v' = if lib.isBool v then
|
v' =
|
||||||
lib.boolToString lib.value
|
if lib.isBool v then
|
||||||
else if lib.isString v then
|
lib.boolToString lib.value
|
||||||
''"${v}"''
|
else if lib.isString v then
|
||||||
else
|
''"${v}"''
|
||||||
toString v;
|
else
|
||||||
in "${lib.escape [ "=" ] n} = ${v'}";
|
toString v;
|
||||||
|
in
|
||||||
|
"${lib.escape [ "=" ] n} = ${v'}";
|
||||||
|
|
||||||
themeType = types.submodule {
|
themeType = types.submodule {
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -100,7 +109,8 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.rycee ];
|
meta.maintainers = [ lib.maintainers.rycee ];
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
|
|
@ -153,10 +163,8 @@ in {
|
||||||
configLocation = mkOption {
|
configLocation = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "${config.home.homeDirectory}/.gtkrc-2.0";
|
default = "${config.home.homeDirectory}/.gtkrc-2.0";
|
||||||
defaultText =
|
defaultText = literalExpression ''"''${config.home.homeDirectory}/.gtkrc-2.0"'';
|
||||||
literalExpression ''"''${config.home.homeDirectory}/.gtkrc-2.0"'';
|
example = literalExpression ''"''${config.xdg.configHome}/gtk-2.0/gtkrc"'';
|
||||||
example =
|
|
||||||
literalExpression ''"''${config.xdg.configHome}/gtk-2.0/gtkrc"'';
|
|
||||||
description = ''
|
description = ''
|
||||||
The location to put the GTK configuration file.
|
The location to put the GTK configuration file.
|
||||||
'';
|
'';
|
||||||
|
|
@ -172,7 +180,13 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
extraConfig = mkOption {
|
extraConfig = mkOption {
|
||||||
type = with types; attrsOf (oneOf [ bool int str ]);
|
type =
|
||||||
|
with types;
|
||||||
|
attrsOf (oneOf [
|
||||||
|
bool
|
||||||
|
int
|
||||||
|
str
|
||||||
|
]);
|
||||||
default = { };
|
default = { };
|
||||||
example = {
|
example = {
|
||||||
gtk-cursor-blink = false;
|
gtk-cursor-blink = false;
|
||||||
|
|
@ -220,75 +234,86 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable (let
|
config = lib.mkIf cfg.enable (
|
||||||
gtkIni = optionalAttrs (cfg.font != null) {
|
let
|
||||||
gtk-font-name =
|
gtkIni =
|
||||||
let fontSize = if cfg.font.size != null then cfg.font.size else 10;
|
optionalAttrs (cfg.font != null) {
|
||||||
in "${cfg.font.name} ${toString fontSize}";
|
gtk-font-name =
|
||||||
} // optionalAttrs (cfg.theme != null) { gtk-theme-name = cfg.theme.name; }
|
let
|
||||||
// optionalAttrs (cfg.iconTheme != null) {
|
fontSize = if cfg.font.size != null then cfg.font.size else 10;
|
||||||
gtk-icon-theme-name = cfg.iconTheme.name;
|
in
|
||||||
} // optionalAttrs (cfg.cursorTheme != null) {
|
"${cfg.font.name} ${toString fontSize}";
|
||||||
gtk-cursor-theme-name = cfg.cursorTheme.name;
|
}
|
||||||
} // optionalAttrs
|
// optionalAttrs (cfg.theme != null) { gtk-theme-name = cfg.theme.name; }
|
||||||
(cfg.cursorTheme != null && cfg.cursorTheme.size != null) {
|
// optionalAttrs (cfg.iconTheme != null) {
|
||||||
gtk-cursor-theme-size = cfg.cursorTheme.size;
|
gtk-icon-theme-name = cfg.iconTheme.name;
|
||||||
|
}
|
||||||
|
// optionalAttrs (cfg.cursorTheme != null) {
|
||||||
|
gtk-cursor-theme-name = cfg.cursorTheme.name;
|
||||||
|
}
|
||||||
|
// optionalAttrs (cfg.cursorTheme != null && cfg.cursorTheme.size != null) {
|
||||||
|
gtk-cursor-theme-size = cfg.cursorTheme.size;
|
||||||
|
};
|
||||||
|
|
||||||
|
gtk4Css =
|
||||||
|
lib.optionalString (cfg.theme != null && cfg.theme.package != null) ''
|
||||||
|
/**
|
||||||
|
* GTK 4 reads the theme configured by gtk-theme-name, but ignores it.
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
// optionalAttrs (cfg.iconTheme != null) {
|
||||||
|
icon-theme = cfg.iconTheme.name;
|
||||||
|
}
|
||||||
|
// optionalAttrs (cfg.cursorTheme != null) {
|
||||||
|
cursor-theme = cfg.cursorTheme.name;
|
||||||
|
}
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
home.packages = lib.concatMap optionalPackage [
|
||||||
|
cfg.font
|
||||||
|
cfg.theme
|
||||||
|
cfg.iconTheme
|
||||||
|
cfg.cursorTheme
|
||||||
|
];
|
||||||
|
|
||||||
|
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/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;
|
||||||
};
|
};
|
||||||
|
|
||||||
gtk4Css =
|
xdg.configFile."gtk-4.0/settings.ini".text = toGtk3Ini { Settings = gtkIni // cfg4.extraConfig; };
|
||||||
lib.optionalString (cfg.theme != null && cfg.theme.package != null) ''
|
|
||||||
/**
|
|
||||||
* GTK 4 reads the theme configured by gtk-theme-name, but ignores it.
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
dconfIni = optionalAttrs (cfg.font != null) {
|
xdg.configFile."gtk-4.0/gtk.css" = lib.mkIf (gtk4Css != "") { text = gtk4Css; };
|
||||||
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; }
|
|
||||||
// optionalAttrs (cfg.iconTheme != null) {
|
|
||||||
icon-theme = cfg.iconTheme.name;
|
|
||||||
} // optionalAttrs (cfg.cursorTheme != null) {
|
|
||||||
cursor-theme = cfg.cursorTheme.name;
|
|
||||||
} // optionalAttrs
|
|
||||||
(cfg.cursorTheme != null && cfg.cursorTheme.size != null) {
|
|
||||||
cursor-size = cfg.cursorTheme.size;
|
|
||||||
};
|
|
||||||
|
|
||||||
optionalPackage = opt:
|
dconf.settings."org/gnome/desktop/interface" = dconfIni;
|
||||||
lib.optional (opt != null && opt.package != null) opt.package;
|
}
|
||||||
in {
|
);
|
||||||
home.packages = lib.concatMap optionalPackage [
|
|
||||||
cfg.font
|
|
||||||
cfg.theme
|
|
||||||
cfg.iconTheme
|
|
||||||
cfg.cursorTheme
|
|
||||||
];
|
|
||||||
|
|
||||||
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/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/gtk.css" =
|
|
||||||
lib.mkIf (gtk4Css != "") { text = gtk4Css; };
|
|
||||||
|
|
||||||
dconf.settings."org/gnome/desktop/interface" = dconfIni;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (pkgs.stdenv) isDarwin;
|
inherit (pkgs.stdenv) isDarwin;
|
||||||
|
|
@ -10,16 +15,16 @@ let
|
||||||
(pkgs.writeTextDir "lib/mozilla/native-messaging-hosts/.keep" "")
|
(pkgs.writeTextDir "lib/mozilla/native-messaging-hosts/.keep" "")
|
||||||
];
|
];
|
||||||
|
|
||||||
thunderbirdNativeMessagingHostsPath = if isDarwin then
|
thunderbirdNativeMessagingHostsPath =
|
||||||
"Library/Mozilla/NativeMessagingHosts"
|
if isDarwin then "Library/Mozilla/NativeMessagingHosts" else ".mozilla/native-messaging-hosts";
|
||||||
else
|
|
||||||
".mozilla/native-messaging-hosts";
|
|
||||||
|
|
||||||
firefoxNativeMessagingHostsPath = if isDarwin then
|
firefoxNativeMessagingHostsPath =
|
||||||
"Library/Application Support/Mozilla/NativeMessagingHosts"
|
if isDarwin then
|
||||||
else
|
"Library/Application Support/Mozilla/NativeMessagingHosts"
|
||||||
".mozilla/native-messaging-hosts";
|
else
|
||||||
in {
|
".mozilla/native-messaging-hosts";
|
||||||
|
in
|
||||||
|
{
|
||||||
meta.maintainers = with lib.maintainers; [
|
meta.maintainers = with lib.maintainers; [
|
||||||
booxter
|
booxter
|
||||||
rycee
|
rycee
|
||||||
|
|
@ -46,47 +51,45 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf (cfg.firefoxNativeMessagingHosts != [ ]
|
config =
|
||||||
|| cfg.thunderbirdNativeMessagingHosts != [ ]) {
|
lib.mkIf (cfg.firefoxNativeMessagingHosts != [ ] || cfg.thunderbirdNativeMessagingHosts != [ ])
|
||||||
home.file = if isDarwin then
|
{
|
||||||
let
|
home.file =
|
||||||
firefoxNativeMessagingHostsJoined = pkgs.symlinkJoin {
|
if isDarwin then
|
||||||
name = "ff-native-messaging-hosts";
|
let
|
||||||
paths = defaultPaths ++ cfg.firefoxNativeMessagingHosts;
|
firefoxNativeMessagingHostsJoined = pkgs.symlinkJoin {
|
||||||
};
|
name = "ff-native-messaging-hosts";
|
||||||
thunderbirdNativeMessagingHostsJoined = pkgs.symlinkJoin {
|
paths = defaultPaths ++ cfg.firefoxNativeMessagingHosts;
|
||||||
name = "th-native-messaging-hosts";
|
};
|
||||||
paths = defaultPaths ++ cfg.thunderbirdNativeMessagingHosts;
|
thunderbirdNativeMessagingHostsJoined = pkgs.symlinkJoin {
|
||||||
};
|
name = "th-native-messaging-hosts";
|
||||||
in {
|
paths = defaultPaths ++ cfg.thunderbirdNativeMessagingHosts;
|
||||||
"${thunderbirdNativeMessagingHostsPath}" =
|
};
|
||||||
lib.mkIf (cfg.thunderbirdNativeMessagingHosts != [ ]) {
|
in
|
||||||
source =
|
{
|
||||||
"${thunderbirdNativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
|
"${thunderbirdNativeMessagingHostsPath}" = lib.mkIf (cfg.thunderbirdNativeMessagingHosts != [ ]) {
|
||||||
recursive = true;
|
source = "${thunderbirdNativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
|
||||||
};
|
recursive = true;
|
||||||
|
};
|
||||||
|
|
||||||
"${firefoxNativeMessagingHostsPath}" =
|
"${firefoxNativeMessagingHostsPath}" = lib.mkIf (cfg.firefoxNativeMessagingHosts != [ ]) {
|
||||||
lib.mkIf (cfg.firefoxNativeMessagingHosts != [ ]) {
|
source = "${firefoxNativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
|
||||||
source =
|
recursive = true;
|
||||||
"${firefoxNativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
|
};
|
||||||
recursive = true;
|
}
|
||||||
|
else
|
||||||
|
let
|
||||||
|
nativeMessagingHostsJoined = pkgs.symlinkJoin {
|
||||||
|
name = "mozilla-native-messaging-hosts";
|
||||||
|
# on Linux, the directory is shared between Firefox and Thunderbird; merge both into one
|
||||||
|
paths = defaultPaths ++ cfg.firefoxNativeMessagingHosts ++ cfg.thunderbirdNativeMessagingHosts;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
"${firefoxNativeMessagingHostsPath}" = {
|
||||||
|
source = "${nativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
|
||||||
|
recursive = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
else
|
|
||||||
let
|
|
||||||
nativeMessagingHostsJoined = pkgs.symlinkJoin {
|
|
||||||
name = "mozilla-native-messaging-hosts";
|
|
||||||
# on Linux, the directory is shared between Firefox and Thunderbird; merge both into one
|
|
||||||
paths = defaultPaths ++ cfg.firefoxNativeMessagingHosts
|
|
||||||
++ cfg.thunderbirdNativeMessagingHosts;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
"${firefoxNativeMessagingHostsPath}" = {
|
|
||||||
source =
|
|
||||||
"${nativeMessagingHostsJoined}/lib/mozilla/native-messaging-hosts";
|
|
||||||
recursive = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types;
|
||||||
|
|
@ -7,58 +12,64 @@ let
|
||||||
|
|
||||||
hostPlatform = pkgs.stdenv.hostPlatform;
|
hostPlatform = pkgs.stdenv.hostPlatform;
|
||||||
|
|
||||||
entryModule = types.submodule ({ config, ... }: {
|
entryModule = types.submodule (
|
||||||
options = {
|
{ config, ... }:
|
||||||
id = mkOption {
|
{
|
||||||
internal = true;
|
options = {
|
||||||
type = types.str;
|
id = mkOption {
|
||||||
description = ''
|
internal = true;
|
||||||
A unique entry identifier. By default it is a base16
|
type = types.str;
|
||||||
formatted hash of the entry message.
|
description = ''
|
||||||
'';
|
A unique entry identifier. By default it is a base16
|
||||||
|
formatted hash of the entry message.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
time = mkOption {
|
||||||
|
internal = true;
|
||||||
|
type = types.str;
|
||||||
|
example = "2017-07-10T21:55:04+00:00";
|
||||||
|
description = ''
|
||||||
|
News entry time stamp in ISO-8601 format. Must be in UTC
|
||||||
|
(ending in '+00:00').
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
condition = mkOption {
|
||||||
|
internal = true;
|
||||||
|
default = true;
|
||||||
|
description = "Whether the news entry should be active.";
|
||||||
|
};
|
||||||
|
|
||||||
|
message = mkOption {
|
||||||
|
internal = true;
|
||||||
|
type = types.str;
|
||||||
|
description = "The news entry content.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
time = mkOption {
|
config = {
|
||||||
internal = true;
|
id = lib.mkDefault (builtins.hashString "sha256" config.message);
|
||||||
type = types.str;
|
|
||||||
example = "2017-07-10T21:55:04+00:00";
|
|
||||||
description = ''
|
|
||||||
News entry time stamp in ISO-8601 format. Must be in UTC
|
|
||||||
(ending in '+00:00').
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
condition = mkOption {
|
);
|
||||||
internal = true;
|
|
||||||
default = true;
|
|
||||||
description = "Whether the news entry should be active.";
|
|
||||||
};
|
|
||||||
|
|
||||||
message = mkOption {
|
|
||||||
internal = true;
|
|
||||||
type = types.str;
|
|
||||||
description = "The news entry content.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
id = lib.mkDefault (builtins.hashString "sha256" config.message);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
isNixFile = n: v: v == "regular" && lib.hasSuffix ".nix" n;
|
isNixFile = n: v: v == "regular" && lib.hasSuffix ".nix" n;
|
||||||
# builtins.attrNames return the values in alphabetical order
|
# builtins.attrNames return the values in alphabetical order
|
||||||
newsFiles =
|
newsFiles = builtins.attrNames (lib.filterAttrs isNixFile (builtins.readDir ./news));
|
||||||
builtins.attrNames (lib.filterAttrs isNixFile (builtins.readDir ./news));
|
newsEntries = builtins.map (newsFile: import (./news + "/${newsFile}")) newsFiles;
|
||||||
newsEntries =
|
in
|
||||||
builtins.map (newsFile: import (./news + "/${newsFile}")) newsFiles;
|
{
|
||||||
in {
|
|
||||||
meta.maintainers = [ lib.maintainers.rycee ];
|
meta.maintainers = [ lib.maintainers.rycee ];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
news = {
|
news = {
|
||||||
display = mkOption {
|
display = mkOption {
|
||||||
type = types.enum [ "silent" "notify" "show" ];
|
type = types.enum [
|
||||||
|
"silent"
|
||||||
|
"notify"
|
||||||
|
"show"
|
||||||
|
];
|
||||||
default = "notify";
|
default = "notify";
|
||||||
description = ''
|
description = ''
|
||||||
How unread and relevant news should be presented when
|
How unread and relevant news should be presented when
|
||||||
|
|
@ -100,8 +111,9 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
news.json.output = pkgs.writeText "hm-news.json"
|
news.json.output = pkgs.writeText "hm-news.json" (
|
||||||
(builtins.toJSON { inherit (cfg) display entries; });
|
builtins.toJSON { inherit (cfg) display entries; }
|
||||||
|
);
|
||||||
|
|
||||||
# DO NOT define new entries here, instead use the `./create-news-entry.sh`
|
# DO NOT define new entries here, instead use the `./create-news-entry.sh`
|
||||||
# script and create an individual news file inside `news` sub-directory.
|
# script and create an individual news file inside `news` sub-directory.
|
||||||
|
|
@ -250,8 +262,7 @@ in {
|
||||||
|
|
||||||
{
|
{
|
||||||
time = "2021-09-23T17:04:48+00:00";
|
time = "2021-09-23T17:04:48+00:00";
|
||||||
condition = hostPlatform.isLinux
|
condition = hostPlatform.isLinux && config.services.screen-locker.enable;
|
||||||
&& config.services.screen-locker.enable;
|
|
||||||
message = ''
|
message = ''
|
||||||
'xautolock' is now optional in 'services.screen-locker', and the
|
'xautolock' is now optional in 'services.screen-locker', and the
|
||||||
'services.screen-locker' options have been reorganized for clarity.
|
'services.screen-locker' options have been reorganized for clarity.
|
||||||
|
|
@ -1699,9 +1710,12 @@ in {
|
||||||
|
|
||||||
{
|
{
|
||||||
time = "2024-06-26T07:07:17+00:00";
|
time = "2024-06-26T07:07:17+00:00";
|
||||||
condition = with config.programs.yazi;
|
condition =
|
||||||
enable && (enableBashIntegration || enableZshIntegration
|
with config.programs.yazi;
|
||||||
|| enableFishIntegration || enableNushellIntegration);
|
enable
|
||||||
|
&& (
|
||||||
|
enableBashIntegration || enableZshIntegration || enableFishIntegration || enableNushellIntegration
|
||||||
|
);
|
||||||
message = ''
|
message = ''
|
||||||
Yazi's shell integration wrappers have been renamed from 'ya' to 'yy'.
|
Yazi's shell integration wrappers have been renamed from 'ya' to 'yy'.
|
||||||
|
|
||||||
|
|
@ -1881,10 +1895,12 @@ in {
|
||||||
|
|
||||||
{
|
{
|
||||||
time = "2024-12-04T20:00:00+00:00";
|
time = "2024-12-04T20:00:00+00:00";
|
||||||
condition = let
|
condition =
|
||||||
sCfg = config.programs.starship;
|
let
|
||||||
fCfg = config.programs.fish;
|
sCfg = config.programs.starship;
|
||||||
in sCfg.enable && sCfg.enableFishIntegration && fCfg.enable;
|
fCfg = config.programs.fish;
|
||||||
|
in
|
||||||
|
sCfg.enable && sCfg.enableFishIntegration && fCfg.enable;
|
||||||
message = ''
|
message = ''
|
||||||
A new option 'programs.starship.enableInteractive' is available for
|
A new option 'programs.starship.enableInteractive' is available for
|
||||||
the Fish shell that only enables starship if the shell is interactive.
|
the Fish shell that only enables starship if the shell is interactive.
|
||||||
|
|
@ -1894,10 +1910,11 @@ in {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
time = "2024-12-08T17:22:13+00:00";
|
time = "2024-12-08T17:22:13+00:00";
|
||||||
condition = let
|
condition =
|
||||||
usingMbsync = lib.any (a: a.mbsync.enable)
|
let
|
||||||
(lib.attrValues config.accounts.email.accounts);
|
usingMbsync = lib.any (a: a.mbsync.enable) (lib.attrValues config.accounts.email.accounts);
|
||||||
in usingMbsync;
|
in
|
||||||
|
usingMbsync;
|
||||||
message = ''
|
message = ''
|
||||||
isync/mbsync 1.5.0 has changed several things.
|
isync/mbsync 1.5.0 has changed several things.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,38 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
boolToString concatStringsSep escape floatToString getVersion isBool
|
boolToString
|
||||||
isConvertibleWithToString isDerivation isFloat isInt isList isString
|
concatStringsSep
|
||||||
literalExpression maintainers mapAttrsToList mkDefault mkEnableOption mkIf
|
escape
|
||||||
mkMerge mkOption optionalString toPretty types versionAtLeast;
|
floatToString
|
||||||
|
getVersion
|
||||||
|
isBool
|
||||||
|
isConvertibleWithToString
|
||||||
|
isDerivation
|
||||||
|
isFloat
|
||||||
|
isInt
|
||||||
|
isList
|
||||||
|
isString
|
||||||
|
literalExpression
|
||||||
|
maintainers
|
||||||
|
mapAttrsToList
|
||||||
|
mkDefault
|
||||||
|
mkEnableOption
|
||||||
|
mkIf
|
||||||
|
mkMerge
|
||||||
|
mkOption
|
||||||
|
optionalString
|
||||||
|
toPretty
|
||||||
|
types
|
||||||
|
versionAtLeast
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.nix;
|
cfg = config.nix;
|
||||||
|
|
||||||
|
|
@ -16,29 +42,33 @@ let
|
||||||
|
|
||||||
nixPath = concatStringsSep ":" cfg.nixPath;
|
nixPath = concatStringsSep ":" cfg.nixPath;
|
||||||
|
|
||||||
useXdg = config.nix.enable
|
useXdg = config.nix.enable && (config.nix.settings.use-xdg-base-directories or false);
|
||||||
&& (config.nix.settings.use-xdg-base-directories or false);
|
defexprDir =
|
||||||
defexprDir = if useXdg then
|
if useXdg then
|
||||||
"${config.xdg.stateHome}/nix/defexpr"
|
"${config.xdg.stateHome}/nix/defexpr"
|
||||||
else
|
else
|
||||||
"${config.home.homeDirectory}/.nix-defexpr";
|
"${config.home.homeDirectory}/.nix-defexpr";
|
||||||
|
|
||||||
# The deploy path for declarative channels. The directory name is prefixed
|
# The deploy path for declarative channels. The directory name is prefixed
|
||||||
# with a number to make it easier for files in defexprDir to control the order
|
# with a number to make it easier for files in defexprDir to control the order
|
||||||
# they'll be read relative to each other.
|
# they'll be read relative to each other.
|
||||||
channelPath = "${defexprDir}/50-home-manager";
|
channelPath = "${defexprDir}/50-home-manager";
|
||||||
|
|
||||||
channelsDrv = let
|
channelsDrv =
|
||||||
mkEntry = name: drv: {
|
let
|
||||||
inherit name;
|
mkEntry = name: drv: {
|
||||||
path = toString 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
|
let
|
||||||
|
|
||||||
mkValueString = v:
|
mkValueString =
|
||||||
|
v:
|
||||||
if v == null then
|
if v == null then
|
||||||
""
|
""
|
||||||
else if isInt v then
|
else if isInt v then
|
||||||
|
|
@ -62,10 +92,10 @@ let
|
||||||
|
|
||||||
mkKeyValue = k: v: "${escape [ "=" ] k} = ${mkValueString v}";
|
mkKeyValue = k: v: "${escape [ "=" ] k} = ${mkValueString v}";
|
||||||
|
|
||||||
mkKeyValuePairs = attrs:
|
mkKeyValuePairs = attrs: concatStringsSep "\n" (mapAttrsToList mkKeyValue attrs);
|
||||||
concatStringsSep "\n" (mapAttrsToList mkKeyValue attrs);
|
|
||||||
|
|
||||||
in pkgs.writeTextFile {
|
in
|
||||||
|
pkgs.writeTextFile {
|
||||||
name = "nix.conf";
|
name = "nix.conf";
|
||||||
text = ''
|
text = ''
|
||||||
# WARNING: this file is generated from the nix.settings option in
|
# WARNING: this file is generated from the nix.settings option in
|
||||||
|
|
@ -75,48 +105,58 @@ let
|
||||||
${cfg.extraOptions}
|
${cfg.extraOptions}
|
||||||
'';
|
'';
|
||||||
checkPhase =
|
checkPhase =
|
||||||
if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then ''
|
if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then
|
||||||
echo "Ignoring validation for cross-compilation"
|
''
|
||||||
'' else
|
echo "Ignoring validation for cross-compilation"
|
||||||
|
''
|
||||||
|
else
|
||||||
let
|
let
|
||||||
showCommand =
|
showCommand = if isNixAtLeast "2.20pre" then "config show" else "show-config";
|
||||||
if isNixAtLeast "2.20pre" then "config show" else "show-config";
|
in
|
||||||
in ''
|
''
|
||||||
echo "Validating generated nix.conf"
|
echo "Validating generated nix.conf"
|
||||||
ln -s $out ./nix.conf
|
ln -s $out ./nix.conf
|
||||||
set -e
|
set -e
|
||||||
set +o pipefail
|
set +o pipefail
|
||||||
NIX_CONF_DIR=$PWD \
|
NIX_CONF_DIR=$PWD \
|
||||||
${cfg.package}/bin/nix ${showCommand} ${
|
${cfg.package}/bin/nix ${showCommand} ${optionalString (isNixAtLeast "2.3pre") "--no-net --option experimental-features nix-command"} \
|
||||||
optionalString (isNixAtLeast "2.3pre")
|
|
||||||
"--no-net --option experimental-features nix-command"
|
|
||||||
} \
|
|
||||||
|& sed -e 's/^warning:/error:/' \
|
|& sed -e 's/^warning:/error:/' \
|
||||||
| (! grep '${
|
| (! grep '${if cfg.checkConfig then "^error:" else "^error: unknown setting"}')
|
||||||
if cfg.checkConfig then "^error:" else "^error: unknown setting"
|
|
||||||
}')
|
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
semanticConfType = with types;
|
semanticConfType =
|
||||||
|
with types;
|
||||||
let
|
let
|
||||||
confAtom = nullOr (oneOf [ bool int float str path package ]) // {
|
confAtom =
|
||||||
description =
|
nullOr (oneOf [
|
||||||
"Nix config atom (null, bool, int, float, str, path or package)";
|
bool
|
||||||
};
|
int
|
||||||
in attrsOf (either confAtom (listOf confAtom));
|
float
|
||||||
|
str
|
||||||
|
path
|
||||||
|
package
|
||||||
|
])
|
||||||
|
// {
|
||||||
|
description = "Nix config atom (null, bool, int, float, str, path or package)";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
attrsOf (either confAtom (listOf confAtom));
|
||||||
|
|
||||||
jsonFormat = pkgs.formats.json { };
|
jsonFormat = pkgs.formats.json { };
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options.nix = {
|
options.nix = {
|
||||||
enable = mkEnableOption ''
|
enable =
|
||||||
the Nix configuration module
|
mkEnableOption ''
|
||||||
'' // {
|
the Nix configuration module
|
||||||
default = true;
|
''
|
||||||
visible = false;
|
// {
|
||||||
};
|
default = true;
|
||||||
|
visible = false;
|
||||||
|
};
|
||||||
|
|
||||||
package = mkOption {
|
package = mkOption {
|
||||||
type = types.nullOr types.package;
|
type = types.nullOr types.package;
|
||||||
|
|
@ -169,60 +209,74 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
registry = mkOption {
|
registry = mkOption {
|
||||||
type = types.attrsOf (types.submodule (let
|
type = types.attrsOf (
|
||||||
inputAttrs = types.attrsOf
|
types.submodule (
|
||||||
(types.oneOf [ types.str types.int types.bool types.package ]);
|
let
|
||||||
in { config, name, ... }: {
|
inputAttrs = types.attrsOf (
|
||||||
options = {
|
types.oneOf [
|
||||||
from = mkOption {
|
types.str
|
||||||
type = inputAttrs;
|
types.int
|
||||||
example = {
|
types.bool
|
||||||
type = "indirect";
|
types.package
|
||||||
id = "nixpkgs";
|
]
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{ config, name, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
from = mkOption {
|
||||||
|
type = inputAttrs;
|
||||||
|
example = {
|
||||||
|
type = "indirect";
|
||||||
|
id = "nixpkgs";
|
||||||
|
};
|
||||||
|
description = "The flake reference to be rewritten.";
|
||||||
|
};
|
||||||
|
to = mkOption {
|
||||||
|
type = inputAttrs;
|
||||||
|
example = {
|
||||||
|
type = "github";
|
||||||
|
owner = "my-org";
|
||||||
|
repo = "my-nixpkgs";
|
||||||
|
};
|
||||||
|
description = "The flake reference to which {option}`from>` is to be rewritten.";
|
||||||
|
};
|
||||||
|
flake = mkOption {
|
||||||
|
type = types.nullOr types.attrs;
|
||||||
|
default = null;
|
||||||
|
example = literalExpression "nixpkgs";
|
||||||
|
description = ''
|
||||||
|
The flake input to which {option}`from>` is to be rewritten.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
exact = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Whether the {option}`from` reference needs to match exactly. If set,
|
||||||
|
a {option}`from` reference like `nixpkgs` does not
|
||||||
|
match with a reference like `nixpkgs/nixos-20.03`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
description = "The flake reference to be rewritten.";
|
config = {
|
||||||
};
|
from = mkDefault {
|
||||||
to = mkOption {
|
type = "indirect";
|
||||||
type = inputAttrs;
|
id = name;
|
||||||
example = {
|
};
|
||||||
type = "github";
|
to = mkIf (config.flake != null) (
|
||||||
owner = "my-org";
|
{
|
||||||
repo = "my-nixpkgs";
|
type = "path";
|
||||||
|
path = config.flake.outPath;
|
||||||
|
}
|
||||||
|
// lib.filterAttrs (
|
||||||
|
n: v: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash"
|
||||||
|
) config.flake
|
||||||
|
);
|
||||||
};
|
};
|
||||||
description =
|
}
|
||||||
"The flake reference to which {option}`from>` is to be rewritten.";
|
)
|
||||||
};
|
);
|
||||||
flake = mkOption {
|
|
||||||
type = types.nullOr types.attrs;
|
|
||||||
default = null;
|
|
||||||
example = literalExpression "nixpkgs";
|
|
||||||
description = ''
|
|
||||||
The flake input to which {option}`from>` is to be rewritten.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
exact = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description = ''
|
|
||||||
Whether the {option}`from` reference needs to match exactly. If set,
|
|
||||||
a {option}`from` reference like `nixpkgs` does not
|
|
||||||
match with a reference like `nixpkgs/nixos-20.03`.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config = {
|
|
||||||
from = mkDefault {
|
|
||||||
type = "indirect";
|
|
||||||
id = name;
|
|
||||||
};
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
default = { };
|
default = { };
|
||||||
description = ''
|
description = ''
|
||||||
User level flake registry.
|
User level flake registry.
|
||||||
|
|
@ -290,22 +344,22 @@ in {
|
||||||
})
|
})
|
||||||
|
|
||||||
(mkIf (cfg.registry != { }) {
|
(mkIf (cfg.registry != { }) {
|
||||||
xdg.configFile."nix/registry.json".source =
|
xdg.configFile."nix/registry.json".source = jsonFormat.generate "registry.json" {
|
||||||
jsonFormat.generate "registry.json" {
|
version = cfg.registryVersion;
|
||||||
version = cfg.registryVersion;
|
flakes = 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 != "") {
|
(mkIf (cfg.settings != { } || cfg.extraOptions != "") {
|
||||||
assertions = [{
|
assertions = [
|
||||||
assertion = cfg.package != null;
|
{
|
||||||
message = ''
|
assertion = cfg.package != null;
|
||||||
A corresponding Nix package must be specified via `nix.package` for generating
|
message = ''
|
||||||
nix.conf.
|
A corresponding Nix package must be specified via `nix.package` for generating
|
||||||
'';
|
nix.conf.
|
||||||
}];
|
'';
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
xdg.configFile."nix/nix.conf".source = nixConf;
|
xdg.configFile."nix/nix.conf".source = nixConf;
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,23 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.nixGL;
|
cfg = config.nixGL;
|
||||||
wrapperListMarkdown = with builtins;
|
wrapperListMarkdown =
|
||||||
foldl' (list: name:
|
with builtins;
|
||||||
list + ''
|
foldl' (
|
||||||
|
list: name:
|
||||||
|
list
|
||||||
|
+ ''
|
||||||
- ${name}
|
- ${name}
|
||||||
'') "" (attrNames config.lib.nixGL.wrappers);
|
''
|
||||||
in {
|
) "" (attrNames config.lib.nixGL.wrappers);
|
||||||
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.smona ];
|
meta.maintainers = [ lib.maintainers.smona ];
|
||||||
|
|
||||||
options.nixGL = {
|
options.nixGL = {
|
||||||
|
|
@ -93,7 +103,12 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
prime.installScript = lib.mkOption {
|
prime.installScript = lib.mkOption {
|
||||||
type = with lib.types; nullOr (enum [ "mesa" "nvidia" ]);
|
type =
|
||||||
|
with lib.types;
|
||||||
|
nullOr (enum [
|
||||||
|
"mesa"
|
||||||
|
"nvidia"
|
||||||
|
]);
|
||||||
default = null;
|
default = null;
|
||||||
example = "mesa";
|
example = "mesa";
|
||||||
description = ''
|
description = ''
|
||||||
|
|
@ -109,10 +124,12 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
installScripts = lib.mkOption {
|
installScripts = lib.mkOption {
|
||||||
type = with lib.types;
|
type = with lib.types; nullOr (listOf (enum (builtins.attrNames config.lib.nixGL.wrappers)));
|
||||||
nullOr (listOf (enum (builtins.attrNames config.lib.nixGL.wrappers)));
|
|
||||||
default = null;
|
default = null;
|
||||||
example = [ "mesa" "mesaPrime" ];
|
example = [
|
||||||
|
"mesa"
|
||||||
|
"mesaPrime"
|
||||||
|
];
|
||||||
description = ''
|
description = ''
|
||||||
For each wrapper `wrp` named in the provided list, a wrapper script
|
For each wrapper `wrp` named in the provided list, a wrapper script
|
||||||
named `nixGLWrp` is installed into the environment. These scripts are
|
named `nixGLWrp` is installed into the environment. These scripts are
|
||||||
|
|
@ -137,168 +154,199 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let
|
config =
|
||||||
findWrapperPackage = packageAttr:
|
let
|
||||||
# NixGL has wrapper packages in different places depending on how you
|
findWrapperPackage =
|
||||||
# access it. We want HM configuration to be the same, regardless of how
|
packageAttr:
|
||||||
# NixGL is imported.
|
# NixGL has wrapper packages in different places depending on how you
|
||||||
#
|
# access it. We want HM configuration to be the same, regardless of how
|
||||||
# First, let's see if we have a flake.
|
# NixGL is imported.
|
||||||
if builtins.hasAttr pkgs.system cfg.packages then
|
#
|
||||||
cfg.packages.${pkgs.system}.${packageAttr}
|
# First, let's see if we have a flake.
|
||||||
else
|
if builtins.hasAttr pkgs.system cfg.packages then
|
||||||
# Next, let's see if we have a channel.
|
cfg.packages.${pkgs.system}.${packageAttr}
|
||||||
if builtins.hasAttr packageAttr cfg.packages then
|
|
||||||
cfg.packages.${packageAttr}
|
|
||||||
else
|
|
||||||
# Lastly, with channels, some wrappers are grouped under "auto".
|
|
||||||
if builtins.hasAttr "auto" cfg.packages then
|
|
||||||
cfg.packages.auto.${packageAttr}
|
|
||||||
else
|
|
||||||
throw "Incompatible NixGL package layout";
|
|
||||||
|
|
||||||
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}";
|
|
||||||
|
|
||||||
mesaOffloadEnv = { "DRI_PRIME" = "${cfg.prime.card}"; };
|
|
||||||
|
|
||||||
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 {
|
|
||||||
"__NV_PRIME_RENDER_OFFLOAD_PROVIDER" = "${provider}";
|
|
||||||
} else
|
|
||||||
{ });
|
|
||||||
|
|
||||||
makePackageWrapper = vendor: environment: pkg:
|
|
||||||
if builtins.isNull cfg.packages then
|
|
||||||
pkg
|
|
||||||
else
|
|
||||||
# Wrap the package's binaries with nixGL, while preserving the rest of
|
|
||||||
# the outputs and derivation attributes.
|
|
||||||
(pkg.overrideAttrs (old: {
|
|
||||||
name = "nixGL-${pkg.name}";
|
|
||||||
|
|
||||||
# Make sure this is false for the wrapper derivation, so nix doesn't expect
|
|
||||||
# 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
|
|
||||||
# We need an intermediate wrapper package because makeWrapper
|
|
||||||
# requires a single executable as the wrapper.
|
|
||||||
combinedWrapperPkg =
|
|
||||||
pkgs.writeShellScriptBin "nixGLCombinedWrapper-${vendor}" ''
|
|
||||||
exec ${getWrapperExe vendor} "$@"
|
|
||||||
'';
|
|
||||||
in ''
|
|
||||||
set -eo pipefail
|
|
||||||
|
|
||||||
${ # 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}"
|
|
||||||
set +x
|
|
||||||
'') (old.outputs or [ "out" ]))}
|
|
||||||
|
|
||||||
rm -rf $out/bin/*
|
|
||||||
shopt -s nullglob # Prevent loop from running if no files
|
|
||||||
for file in ${pkg.out}/bin/*; do
|
|
||||||
local prog="$(basename "$file")"
|
|
||||||
makeWrapper \
|
|
||||||
"${lib.getExe combinedWrapperPkg}" \
|
|
||||||
"$out/bin/$prog" \
|
|
||||||
--argv0 "$prog" \
|
|
||||||
--add-flags "$file" \
|
|
||||||
${
|
|
||||||
lib.concatStringsSep " " (lib.attrsets.mapAttrsToList
|
|
||||||
(var: val: "--set '${var}' '${val}'") environment)
|
|
||||||
}
|
|
||||||
done
|
|
||||||
|
|
||||||
# If .desktop files refer to the old package, replace the references
|
|
||||||
for dsk in "$out/share/applications"/*.desktop ; do
|
|
||||||
if ! grep -q "${pkg.out}" "$dsk"; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
src="$(readlink "$dsk")"
|
|
||||||
rm "$dsk"
|
|
||||||
sed "s|${pkg.out}|$out|g" "$src" > "$dsk"
|
|
||||||
done
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
wrappers = {
|
|
||||||
mesa = makePackageWrapper "Intel" { };
|
|
||||||
mesaPrime = makePackageWrapper "Intel" mesaOffloadEnv;
|
|
||||||
nvidia = makePackageWrapper "Nvidia" { };
|
|
||||||
nvidiaPrime = makePackageWrapper "Nvidia" nvOffloadEnv;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
lib.nixGL.wrap = wrappers.${cfg.defaultWrapper};
|
|
||||||
lib.nixGL.wrapOffload = wrappers.${cfg.offloadWrapper};
|
|
||||||
lib.nixGL.wrappers = wrappers;
|
|
||||||
|
|
||||||
home.packages = let
|
|
||||||
wantsPrimeWrapper = (!isNull cfg.prime.installScript);
|
|
||||||
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 mesaOffloadEnv)
|
|
||||||
else
|
else
|
||||||
(envVarsAsScript nvOffloadEnv)}
|
# Next, let's see if we have a channel.
|
||||||
exec "$@"
|
if builtins.hasAttr packageAttr cfg.packages then
|
||||||
''))
|
cfg.packages.${packageAttr}
|
||||||
|
else
|
||||||
|
# Lastly, with channels, some wrappers are grouped under "auto".
|
||||||
|
if builtins.hasAttr "auto" cfg.packages then
|
||||||
|
cfg.packages.auto.${packageAttr}
|
||||||
|
else
|
||||||
|
throw "Incompatible NixGL package layout";
|
||||||
|
|
||||||
(lib.mkIf (wantsWrapper "mesa") (pkgs.writeShellScriptBin "nixGLMesa" ''
|
getWrapperExe =
|
||||||
exec ${getWrapperExe "Intel"} "$@"
|
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}";
|
||||||
|
|
||||||
(lib.mkIf (wantsWrapper "mesaPrime")
|
mesaOffloadEnv = {
|
||||||
(pkgs.writeShellScriptBin "nixGLMesaPrime" ''
|
"DRI_PRIME" = "${cfg.prime.card}";
|
||||||
${envVarsAsScript mesaOffloadEnv}
|
};
|
||||||
exec ${getWrapperExe "Intel"} "$@"
|
|
||||||
''))
|
|
||||||
|
|
||||||
(lib.mkIf (wantsWrapper "nvidia")
|
nvOffloadEnv =
|
||||||
(pkgs.writeShellScriptBin "nixGLNvidia" ''
|
{
|
||||||
exec ${getWrapperExe "Nvidia"} "$@"
|
"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
|
||||||
|
{
|
||||||
|
"__NV_PRIME_RENDER_OFFLOAD_PROVIDER" = "${provider}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ }
|
||||||
|
);
|
||||||
|
|
||||||
(lib.mkIf (wantsWrapper "nvidia")
|
makePackageWrapper =
|
||||||
(pkgs.writeShellScriptBin "nixGLNvidiaPrime" ''
|
vendor: environment: pkg:
|
||||||
${envVarsAsScript nvOffloadEnv}
|
if builtins.isNull cfg.packages then
|
||||||
exec ${getWrapperExe "Nvidia"} "$@"
|
pkg
|
||||||
''))
|
else
|
||||||
];
|
# Wrap the package's binaries with nixGL, while preserving the rest of
|
||||||
};
|
# the outputs and derivation attributes.
|
||||||
|
(pkg.overrideAttrs (old: {
|
||||||
|
name = "nixGL-${pkg.name}";
|
||||||
|
|
||||||
|
# Make sure this is false for the wrapper derivation, so nix doesn't expect
|
||||||
|
# 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
|
||||||
|
# We need an intermediate wrapper package because makeWrapper
|
||||||
|
# requires a single executable as the wrapper.
|
||||||
|
combinedWrapperPkg = pkgs.writeShellScriptBin "nixGLCombinedWrapper-${vendor}" ''
|
||||||
|
exec ${getWrapperExe vendor} "$@"
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
''
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
${
|
||||||
|
# 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}"
|
||||||
|
set +x
|
||||||
|
'') (old.outputs or [ "out" ])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
rm -rf $out/bin/*
|
||||||
|
shopt -s nullglob # Prevent loop from running if no files
|
||||||
|
for file in ${pkg.out}/bin/*; do
|
||||||
|
local prog="$(basename "$file")"
|
||||||
|
makeWrapper \
|
||||||
|
"${lib.getExe combinedWrapperPkg}" \
|
||||||
|
"$out/bin/$prog" \
|
||||||
|
--argv0 "$prog" \
|
||||||
|
--add-flags "$file" \
|
||||||
|
${lib.concatStringsSep " " (
|
||||||
|
lib.attrsets.mapAttrsToList (var: val: "--set '${var}' '${val}'") environment
|
||||||
|
)}
|
||||||
|
done
|
||||||
|
|
||||||
|
# If .desktop files refer to the old package, replace the references
|
||||||
|
for dsk in "$out/share/applications"/*.desktop ; do
|
||||||
|
if ! grep -q "${pkg.out}" "$dsk"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
src="$(readlink "$dsk")"
|
||||||
|
rm "$dsk"
|
||||||
|
sed "s|${pkg.out}|$out|g" "$src" > "$dsk"
|
||||||
|
done
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
wrappers = {
|
||||||
|
mesa = makePackageWrapper "Intel" { };
|
||||||
|
mesaPrime = makePackageWrapper "Intel" mesaOffloadEnv;
|
||||||
|
nvidia = makePackageWrapper "Nvidia" { };
|
||||||
|
nvidiaPrime = makePackageWrapper "Nvidia" nvOffloadEnv;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
lib.nixGL.wrap = wrappers.${cfg.defaultWrapper};
|
||||||
|
lib.nixGL.wrapOffload = wrappers.${cfg.offloadWrapper};
|
||||||
|
lib.nixGL.wrappers = wrappers;
|
||||||
|
|
||||||
|
home.packages =
|
||||||
|
let
|
||||||
|
wantsPrimeWrapper = (!isNull cfg.prime.installScript);
|
||||||
|
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 mesaOffloadEnv)
|
||||||
|
else
|
||||||
|
(envVarsAsScript nvOffloadEnv)
|
||||||
|
}
|
||||||
|
exec "$@"
|
||||||
|
''
|
||||||
|
))
|
||||||
|
|
||||||
|
(lib.mkIf (wantsWrapper "mesa") (
|
||||||
|
pkgs.writeShellScriptBin "nixGLMesa" ''
|
||||||
|
exec ${getWrapperExe "Intel"} "$@"
|
||||||
|
''
|
||||||
|
))
|
||||||
|
|
||||||
|
(lib.mkIf (wantsWrapper "mesaPrime") (
|
||||||
|
pkgs.writeShellScriptBin "nixGLMesaPrime" ''
|
||||||
|
${envVarsAsScript mesaOffloadEnv}
|
||||||
|
exec ${getWrapperExe "Intel"} "$@"
|
||||||
|
''
|
||||||
|
))
|
||||||
|
|
||||||
|
(lib.mkIf (wantsWrapper "nvidia") (
|
||||||
|
pkgs.writeShellScriptBin "nixGLNvidia" ''
|
||||||
|
exec ${getWrapperExe "Nvidia"} "$@"
|
||||||
|
''
|
||||||
|
))
|
||||||
|
|
||||||
|
(lib.mkIf (wantsWrapper "nvidia") (
|
||||||
|
pkgs.writeShellScriptBin "nixGLNvidiaPrime" ''
|
||||||
|
${envVarsAsScript nvOffloadEnv}
|
||||||
|
exec ${getWrapperExe "Nvidia"} "$@"
|
||||||
|
''
|
||||||
|
))
|
||||||
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
|
|
@ -11,16 +16,22 @@ let
|
||||||
optCall = f: x: if builtins.isFunction f then f x else f;
|
optCall = f: x: if builtins.isFunction f then f x else f;
|
||||||
|
|
||||||
# Copied from nixpkgs.nix.
|
# Copied from nixpkgs.nix.
|
||||||
mergeConfig = lhs_: rhs_:
|
mergeConfig =
|
||||||
|
lhs_: rhs_:
|
||||||
let
|
let
|
||||||
lhs = optCall lhs_ { inherit pkgs; };
|
lhs = optCall lhs_ { inherit pkgs; };
|
||||||
rhs = optCall rhs_ { inherit pkgs; };
|
rhs = optCall rhs_ { inherit pkgs; };
|
||||||
in lhs // rhs // lib.optionalAttrs (lhs ? packageOverrides) {
|
in
|
||||||
packageOverrides = pkgs:
|
lhs
|
||||||
optCall lhs.packageOverrides pkgs
|
// rhs
|
||||||
// optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs;
|
// lib.optionalAttrs (lhs ? packageOverrides) {
|
||||||
} // lib.optionalAttrs (lhs ? perlPackageOverrides) {
|
packageOverrides =
|
||||||
perlPackageOverrides = pkgs:
|
pkgs:
|
||||||
|
optCall lhs.packageOverrides pkgs // optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs;
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs (lhs ? perlPackageOverrides) {
|
||||||
|
perlPackageOverrides =
|
||||||
|
pkgs:
|
||||||
optCall lhs.perlPackageOverrides pkgs
|
optCall lhs.perlPackageOverrides pkgs
|
||||||
// optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs;
|
// optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs;
|
||||||
};
|
};
|
||||||
|
|
@ -29,9 +40,12 @@ let
|
||||||
configType = lib.mkOptionType {
|
configType = lib.mkOptionType {
|
||||||
name = "nixpkgs-config";
|
name = "nixpkgs-config";
|
||||||
description = "nixpkgs config";
|
description = "nixpkgs config";
|
||||||
check = x:
|
check =
|
||||||
let traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false;
|
x:
|
||||||
in traceXIfNot isConfig;
|
let
|
||||||
|
traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false;
|
||||||
|
in
|
||||||
|
traceXIfNot isConfig;
|
||||||
merge = args: lib.fold (def: mergeConfig def.value) { };
|
merge = args: lib.fold (def: mergeConfig def.value) { };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -43,7 +57,8 @@ let
|
||||||
merge = lib.mergeOneOption;
|
merge = lib.mergeOneOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = with lib.maintainers; [ thiagokokada ];
|
meta.maintainers = with lib.maintainers; [ thiagokokada ];
|
||||||
|
|
||||||
options.nixpkgs = {
|
options.nixpkgs = {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
# Adapted from Nixpkgs.
|
# Adapted from Nixpkgs.
|
||||||
|
|
||||||
{ config, lib, pkgs, pkgsPath, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
pkgsPath,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
|
|
@ -8,16 +14,22 @@ let
|
||||||
|
|
||||||
optCall = f: x: if builtins.isFunction f then f x else f;
|
optCall = f: x: if builtins.isFunction f then f x else f;
|
||||||
|
|
||||||
mergeConfig = lhs_: rhs_:
|
mergeConfig =
|
||||||
|
lhs_: rhs_:
|
||||||
let
|
let
|
||||||
lhs = optCall lhs_ { inherit pkgs; };
|
lhs = optCall lhs_ { inherit pkgs; };
|
||||||
rhs = optCall rhs_ { inherit pkgs; };
|
rhs = optCall rhs_ { inherit pkgs; };
|
||||||
in lhs // rhs // lib.optionalAttrs (lhs ? packageOverrides) {
|
in
|
||||||
packageOverrides = pkgs:
|
lhs
|
||||||
optCall lhs.packageOverrides pkgs
|
// rhs
|
||||||
// optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs;
|
// lib.optionalAttrs (lhs ? packageOverrides) {
|
||||||
} // lib.optionalAttrs (lhs ? perlPackageOverrides) {
|
packageOverrides =
|
||||||
perlPackageOverrides = pkgs:
|
pkgs:
|
||||||
|
optCall lhs.packageOverrides pkgs // optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs;
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs (lhs ? perlPackageOverrides) {
|
||||||
|
perlPackageOverrides =
|
||||||
|
pkgs:
|
||||||
optCall lhs.perlPackageOverrides pkgs
|
optCall lhs.perlPackageOverrides pkgs
|
||||||
// optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs;
|
// optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs;
|
||||||
};
|
};
|
||||||
|
|
@ -25,9 +37,12 @@ let
|
||||||
configType = lib.mkOptionType {
|
configType = lib.mkOptionType {
|
||||||
name = "nixpkgs-config";
|
name = "nixpkgs-config";
|
||||||
description = "nixpkgs config";
|
description = "nixpkgs config";
|
||||||
check = x:
|
check =
|
||||||
let traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false;
|
x:
|
||||||
in traceXIfNot isConfig;
|
let
|
||||||
|
traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false;
|
||||||
|
in
|
||||||
|
traceXIfNot isConfig;
|
||||||
merge = args: lib.fold (def: mergeConfig def.value) { };
|
merge = args: lib.fold (def: mergeConfig def.value) { };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -40,11 +55,14 @@ let
|
||||||
|
|
||||||
_pkgs = import pkgsPath (lib.filterAttrs (n: v: v != null) config.nixpkgs);
|
_pkgs = import pkgsPath (lib.filterAttrs (n: v: v != null) config.nixpkgs);
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options.nixpkgs = {
|
options.nixpkgs = {
|
||||||
config = lib.mkOption {
|
config = lib.mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
example = { allowBroken = true; };
|
example = {
|
||||||
|
allowBroken = true;
|
||||||
|
};
|
||||||
type = lib.types.nullOr configType;
|
type = lib.types.nullOr configType;
|
||||||
description = ''
|
description = ''
|
||||||
The configuration of the Nix Packages collection. (For
|
The configuration of the Nix Packages collection. (For
|
||||||
|
|
@ -123,10 +141,7 @@ in {
|
||||||
# `_pkgs`, see https://github.com/nix-community/home-manager/pull/993
|
# `_pkgs`, see https://github.com/nix-community/home-manager/pull/993
|
||||||
pkgs = lib.mkOverride lib.modules.defaultOverridePriority _pkgs;
|
pkgs = lib.mkOverride lib.modules.defaultOverridePriority _pkgs;
|
||||||
pkgs_i686 =
|
pkgs_i686 =
|
||||||
if _pkgs.stdenv.isLinux && _pkgs.stdenv.hostPlatform.isx86 then
|
if _pkgs.stdenv.isLinux && _pkgs.stdenv.hostPlatform.isx86 then _pkgs.pkgsi686Linux else { };
|
||||||
_pkgs.pkgsi686Linux
|
|
||||||
else
|
|
||||||
{ };
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,25 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.xsession.numlock;
|
cfg = config.xsession.numlock;
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.evanjs ];
|
meta.maintainers = [ lib.maintainers.evanjs ];
|
||||||
|
|
||||||
options = { xsession.numlock.enable = lib.mkEnableOption "Num Lock"; };
|
options = {
|
||||||
|
xsession.numlock.enable = lib.mkEnableOption "Num Lock";
|
||||||
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
assertions = [
|
assertions = [
|
||||||
(lib.hm.assertions.assertPlatform "xsession.numlock" pkgs
|
(lib.hm.assertions.assertPlatform "xsession.numlock" pkgs lib.platforms.linux)
|
||||||
lib.platforms.linux)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
systemd.user.services.numlockx = {
|
systemd.user.services.numlockx = {
|
||||||
|
|
@ -28,7 +35,9 @@ in {
|
||||||
ExecStart = "${pkgs.numlockx}/bin/numlockx";
|
ExecStart = "${pkgs.numlockx}/bin/numlockx";
|
||||||
};
|
};
|
||||||
|
|
||||||
Install = { WantedBy = [ "graphical-session.target" ]; };
|
Install = {
|
||||||
|
WantedBy = [ "graphical-session.target" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,20 @@ let
|
||||||
|
|
||||||
cfg = config.pam;
|
cfg = config.pam;
|
||||||
|
|
||||||
in {
|
in
|
||||||
meta.maintainers = with lib.maintainers; [ rycee veehaitch ];
|
{
|
||||||
|
meta.maintainers = with lib.maintainers; [
|
||||||
|
rycee
|
||||||
|
veehaitch
|
||||||
|
];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
pam.sessionVariables = lib.mkOption {
|
pam.sessionVariables = lib.mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = lib.types.attrs;
|
type = lib.types.attrs;
|
||||||
example = { EDITOR = "vim"; };
|
example = {
|
||||||
|
EDITOR = "vim";
|
||||||
|
};
|
||||||
description = ''
|
description = ''
|
||||||
Environment variables that will be set for the PAM session.
|
Environment variables that will be set for the PAM session.
|
||||||
The variable values must be as described in
|
The variable values must be as described in
|
||||||
|
|
@ -24,13 +30,15 @@ in {
|
||||||
|
|
||||||
pam.yubico.authorizedYubiKeys = {
|
pam.yubico.authorizedYubiKeys = {
|
||||||
ids = lib.mkOption {
|
ids = lib.mkOption {
|
||||||
type = with lib.types;
|
type =
|
||||||
|
with lib.types;
|
||||||
let
|
let
|
||||||
yubiKeyId = addCheck str (s: lib.stringLength s == 12) // {
|
yubiKeyId = addCheck str (s: lib.stringLength s == 12) // {
|
||||||
name = "yubiKeyId";
|
name = "yubiKeyId";
|
||||||
description = "string of length 12";
|
description = "string of length 12";
|
||||||
};
|
};
|
||||||
in listOf yubiKeyId;
|
in
|
||||||
|
listOf yubiKeyId;
|
||||||
default = [ ];
|
default = [ ];
|
||||||
description = ''
|
description = ''
|
||||||
List of authorized YubiKey token IDs. Refer to
|
List of authorized YubiKey token IDs. Refer to
|
||||||
|
|
@ -52,15 +60,17 @@ in {
|
||||||
|
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
(lib.mkIf (cfg.sessionVariables != { }) {
|
(lib.mkIf (cfg.sessionVariables != { }) {
|
||||||
home.file.".pam_environment".text = lib.concatStringsSep "\n"
|
home.file.".pam_environment".text =
|
||||||
(lib.mapAttrsToList (n: v: ''${n} OVERRIDE="${toString v}"'')
|
lib.concatStringsSep "\n" (
|
||||||
cfg.sessionVariables) + "\n";
|
lib.mapAttrsToList (n: v: ''${n} OVERRIDE="${toString v}"'') cfg.sessionVariables
|
||||||
|
)
|
||||||
|
+ "\n";
|
||||||
})
|
})
|
||||||
|
|
||||||
(lib.mkIf (cfg.yubico.authorizedYubiKeys.ids != [ ]) {
|
(lib.mkIf (cfg.yubico.authorizedYubiKeys.ids != [ ]) {
|
||||||
home.file.${cfg.yubico.authorizedYubiKeys.path}.text =
|
home.file.${cfg.yubico.authorizedYubiKeys.path}.text = lib.concatStringsSep ":" (
|
||||||
lib.concatStringsSep ":"
|
[ config.home.username ] ++ cfg.yubico.authorizedYubiKeys.ids
|
||||||
([ config.home.username ] ++ cfg.yubico.authorizedYubiKeys.ids);
|
);
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,27 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.qt;
|
cfg = config.qt;
|
||||||
|
|
||||||
# Map platform names to their packages.
|
# Map platform names to their packages.
|
||||||
platformPackages = with pkgs; {
|
platformPackages = with pkgs; {
|
||||||
gnome = [ qgnomeplatform qgnomeplatform-qt6 ];
|
gnome = [
|
||||||
adwaita = [ qadwaitadecorations qadwaitadecorations-qt6 ];
|
qgnomeplatform
|
||||||
gtk = [ libsForQt5.qtstyleplugins qt6Packages.qt6gtk2 ];
|
qgnomeplatform-qt6
|
||||||
|
];
|
||||||
|
adwaita = [
|
||||||
|
qadwaitadecorations
|
||||||
|
qadwaitadecorations-qt6
|
||||||
|
];
|
||||||
|
gtk = [
|
||||||
|
libsForQt5.qtstyleplugins
|
||||||
|
qt6Packages.qt6gtk2
|
||||||
|
];
|
||||||
kde = [
|
kde = [
|
||||||
libsForQt5.kio
|
libsForQt5.kio
|
||||||
libsForQt5.plasma-integration
|
libsForQt5.plasma-integration
|
||||||
|
|
@ -18,8 +32,14 @@ let
|
||||||
kdePackages.plasma-integration
|
kdePackages.plasma-integration
|
||||||
kdePackages.systemsettings
|
kdePackages.systemsettings
|
||||||
];
|
];
|
||||||
lxqt = [ lxqt.lxqt-qtplugin lxqt.lxqt-config ];
|
lxqt = [
|
||||||
qtct = [ libsForQt5.qt5ct qt6Packages.qt6ct ];
|
lxqt.lxqt-qtplugin
|
||||||
|
lxqt.lxqt-config
|
||||||
|
];
|
||||||
|
qtct = [
|
||||||
|
libsForQt5.qt5ct
|
||||||
|
qt6Packages.qt6ct
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Maps style names to their QT_QPA_PLATFORMTHEME, if necessary.
|
# Maps style names to their QT_QPA_PLATFORMTHEME, if necessary.
|
||||||
|
|
@ -34,122 +54,181 @@ let
|
||||||
bb10bright = libsForQt5.qtstyleplugins;
|
bb10bright = libsForQt5.qtstyleplugins;
|
||||||
bb10dark = libsForQt5.qtstyleplugins;
|
bb10dark = libsForQt5.qtstyleplugins;
|
||||||
cleanlooks = libsForQt5.qtstyleplugins;
|
cleanlooks = libsForQt5.qtstyleplugins;
|
||||||
gtk2 = [ libsForQt5.qtstyleplugins qt6Packages.qt6gtk2 ];
|
gtk2 = [
|
||||||
|
libsForQt5.qtstyleplugins
|
||||||
|
qt6Packages.qt6gtk2
|
||||||
|
];
|
||||||
motif = libsForQt5.qtstyleplugins;
|
motif = libsForQt5.qtstyleplugins;
|
||||||
cde = libsForQt5.qtstyleplugins;
|
cde = libsForQt5.qtstyleplugins;
|
||||||
plastique = libsForQt5.qtstyleplugins;
|
plastique = libsForQt5.qtstyleplugins;
|
||||||
|
|
||||||
adwaita = [ adwaita-qt adwaita-qt6 ];
|
adwaita = [
|
||||||
adwaita-dark = [ adwaita-qt adwaita-qt6 ];
|
adwaita-qt
|
||||||
adwaita-highcontrast = [ adwaita-qt adwaita-qt6 ];
|
adwaita-qt6
|
||||||
adwaita-highcontrastinverse = [ adwaita-qt adwaita-qt6 ];
|
];
|
||||||
|
adwaita-dark = [
|
||||||
|
adwaita-qt
|
||||||
|
adwaita-qt6
|
||||||
|
];
|
||||||
|
adwaita-highcontrast = [
|
||||||
|
adwaita-qt
|
||||||
|
adwaita-qt6
|
||||||
|
];
|
||||||
|
adwaita-highcontrastinverse = [
|
||||||
|
adwaita-qt
|
||||||
|
adwaita-qt6
|
||||||
|
];
|
||||||
|
|
||||||
breeze = libsForQt5.breeze-qt5;
|
breeze = libsForQt5.breeze-qt5;
|
||||||
|
|
||||||
kvantum =
|
kvantum = [
|
||||||
[ libsForQt5.qtstyleplugin-kvantum qt6Packages.qtstyleplugin-kvantum ];
|
libsForQt5.qtstyleplugin-kvantum
|
||||||
|
qt6Packages.qtstyleplugin-kvantum
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in
|
||||||
meta.maintainers = with lib.maintainers; [ rycee thiagokokada ];
|
{
|
||||||
|
meta.maintainers = with lib.maintainers; [
|
||||||
|
rycee
|
||||||
|
thiagokokada
|
||||||
|
];
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
(lib.mkChangedOptionModule [ "qt" "useGtkTheme" ] [ "qt" "platformTheme" ]
|
(lib.mkChangedOptionModule [ "qt" "useGtkTheme" ] [ "qt" "platformTheme" ] (
|
||||||
(config:
|
config: if lib.getAttrFromPath [ "qt" "useGtkTheme" ] config then "gtk" else null
|
||||||
if lib.getAttrFromPath [ "qt" "useGtkTheme" ] config then
|
))
|
||||||
"gtk"
|
|
||||||
else
|
|
||||||
null))
|
|
||||||
];
|
];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
qt = {
|
qt = {
|
||||||
enable = lib.mkEnableOption "Qt 5 and 6 configuration";
|
enable = lib.mkEnableOption "Qt 5 and 6 configuration";
|
||||||
|
|
||||||
platformTheme = let
|
platformTheme =
|
||||||
newOption = {
|
let
|
||||||
name = lib.mkOption {
|
newOption = {
|
||||||
type = with lib.types; nullOr str;
|
name = lib.mkOption {
|
||||||
default = null;
|
type = with lib.types; nullOr str;
|
||||||
example = "adwaita";
|
default = null;
|
||||||
relatedPackages = [
|
example = "adwaita";
|
||||||
"qgnomeplatform"
|
relatedPackages = [
|
||||||
"qgnomeplatform-qt6"
|
"qgnomeplatform"
|
||||||
"qadwaitadecorations"
|
"qgnomeplatform-qt6"
|
||||||
"qadwaitadecorations-qt6"
|
"qadwaitadecorations"
|
||||||
[ "libsForQt5" "plasma-integration" ]
|
"qadwaitadecorations-qt6"
|
||||||
[ "libsForQt5" "qt5ct" ]
|
[
|
||||||
[ "libsForQt5" "qtstyleplugins" ]
|
"libsForQt5"
|
||||||
[ "libsForQt5" "systemsettings" ]
|
"plasma-integration"
|
||||||
[ "kdePackages" "plasma-integration" ]
|
]
|
||||||
[ "kdePackages" "systemsettings" ]
|
[
|
||||||
[ "lxqt" "lxqt-config" ]
|
"libsForQt5"
|
||||||
[ "lxqt" "lxqt-qtplugin" ]
|
"qt5ct"
|
||||||
[ "qt6Packages" "qt6ct" ]
|
]
|
||||||
[ "qt6Packages" "qt6gtk2" ]
|
[
|
||||||
];
|
"libsForQt5"
|
||||||
description = ''
|
"qtstyleplugins"
|
||||||
Platform theme to use for Qt applications.
|
]
|
||||||
|
[
|
||||||
|
"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.
|
||||||
|
|
||||||
Some examples are
|
Some examples are
|
||||||
|
|
||||||
`gtk`
|
`gtk`
|
||||||
: Use GTK theme with
|
: Use GTK theme with
|
||||||
[`qtstyleplugins`](https://github.com/qt/qtstyleplugins)
|
[`qtstyleplugins`](https://github.com/qt/qtstyleplugins)
|
||||||
|
|
||||||
`gtk3`
|
`gtk3`
|
||||||
: Use [GTK3 integration](https://github.com/qt/qtbase/tree/dev/src/plugins/platformthemes/gtk3)
|
: Use [GTK3 integration](https://github.com/qt/qtbase/tree/dev/src/plugins/platformthemes/gtk3)
|
||||||
for file picker dialogs, font and theme configuration
|
for file picker dialogs, font and theme configuration
|
||||||
|
|
||||||
`adwaita`
|
`adwaita`
|
||||||
: Use Adwaita theme with
|
: Use Adwaita theme with
|
||||||
[`qadwaitadecorations`](https://github.com/FedoraQt/QAdwaitaDecorations)
|
[`qadwaitadecorations`](https://github.com/FedoraQt/QAdwaitaDecorations)
|
||||||
|
|
||||||
`gnome` (deprecated)
|
`gnome` (deprecated)
|
||||||
: Use GNOME theme with
|
: Use GNOME theme with
|
||||||
[`qgnomeplatform`](https://github.com/FedoraQt/QGnomePlatform).
|
[`qgnomeplatform`](https://github.com/FedoraQt/QGnomePlatform).
|
||||||
Is no longer maintained so prefer `adwaita`.
|
Is no longer maintained so prefer `adwaita`.
|
||||||
|
|
||||||
`lxqt`
|
`lxqt`
|
||||||
: Use LXQt theme style set using the
|
: Use LXQt theme style set using the
|
||||||
[`lxqt-config-appearance`](https://github.com/lxqt/lxqt-config)
|
[`lxqt-config-appearance`](https://github.com/lxqt/lxqt-config)
|
||||||
application
|
application
|
||||||
|
|
||||||
`qtct`
|
`qtct`
|
||||||
: Use Qt style set using
|
: Use Qt style set using
|
||||||
[`qt5ct`](https://github.com/desktop-app/qt5ct)
|
[`qt5ct`](https://github.com/desktop-app/qt5ct)
|
||||||
and [`qt6ct`](https://github.com/trialuser02/qt6ct)
|
and [`qt6ct`](https://github.com/trialuser02/qt6ct)
|
||||||
applications
|
applications
|
||||||
|
|
||||||
`kde`
|
`kde`
|
||||||
: Use Qt settings from Plasma 5
|
: Use Qt settings from Plasma 5
|
||||||
|
|
||||||
`kde6`
|
`kde6`
|
||||||
: Use Qt settings from Plasma 6
|
: Use Qt settings from Plasma 6
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
package = lib.mkOption {
|
package = lib.mkOption {
|
||||||
type = with lib.types; nullOr (either package (listOf package));
|
type = with lib.types; nullOr (either package (listOf package));
|
||||||
default = null;
|
default = null;
|
||||||
example =
|
example = lib.literalExpression "[pkgs.adwaita-qt pkgs.adwaita-qt6]";
|
||||||
lib.literalExpression "[pkgs.adwaita-qt pkgs.adwaita-qt6]";
|
description = ''
|
||||||
description = ''
|
Theme package to be used in Qt5/Qt6 applications.
|
||||||
Theme package to be used in Qt5/Qt6 applications.
|
Auto-detected from {option}`qt.platformTheme.name` if possible.
|
||||||
Auto-detected from {option}`qt.platformTheme.name` if possible.
|
See its documentation for available options.
|
||||||
See its documentation for available options.
|
'';
|
||||||
'';
|
};
|
||||||
};
|
};
|
||||||
|
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.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
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.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
style = {
|
style = {
|
||||||
name = lib.mkOption {
|
name = lib.mkOption {
|
||||||
type = with lib.types; nullOr str;
|
type = with lib.types; nullOr str;
|
||||||
|
|
@ -158,11 +237,26 @@ in {
|
||||||
relatedPackages = [
|
relatedPackages = [
|
||||||
"adwaita-qt"
|
"adwaita-qt"
|
||||||
"adwaita-qt6"
|
"adwaita-qt6"
|
||||||
[ "libsForQt5" "breeze-qt5" ]
|
[
|
||||||
[ "libsForQt5" "qtstyleplugin-kvantum" ]
|
"libsForQt5"
|
||||||
[ "libsForQt5" "qtstyleplugins" ]
|
"breeze-qt5"
|
||||||
[ "qt6Packages" "qt6gtk2" ]
|
]
|
||||||
[ "qt6Packages" "qtstyleplugin-kvantum" ]
|
[
|
||||||
|
"libsForQt5"
|
||||||
|
"qtstyleplugin-kvantum"
|
||||||
|
]
|
||||||
|
[
|
||||||
|
"libsForQt5"
|
||||||
|
"qtstyleplugins"
|
||||||
|
]
|
||||||
|
[
|
||||||
|
"qt6Packages"
|
||||||
|
"qt6gtk2"
|
||||||
|
]
|
||||||
|
[
|
||||||
|
"qt6Packages"
|
||||||
|
"qtstyleplugin-kvantum"
|
||||||
|
]
|
||||||
];
|
];
|
||||||
description = ''
|
description = ''
|
||||||
Style to use for Qt5/Qt6 applications. Case-insensitive.
|
Style to use for Qt5/Qt6 applications. Case-insensitive.
|
||||||
|
|
@ -201,80 +295,103 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let
|
config =
|
||||||
platformTheme = if (builtins.isString cfg.platformTheme) then {
|
let
|
||||||
option = "qt.platformTheme";
|
platformTheme =
|
||||||
name = cfg.platformTheme;
|
if (builtins.isString cfg.platformTheme) then
|
||||||
package = null;
|
{
|
||||||
} else if cfg.platformTheme == null then {
|
option = "qt.platformTheme";
|
||||||
option = null;
|
name = cfg.platformTheme;
|
||||||
name = null;
|
package = null;
|
||||||
package = null;
|
}
|
||||||
} else {
|
else if cfg.platformTheme == null then
|
||||||
option = "qt.platformTheme.name";
|
{
|
||||||
name = cfg.platformTheme.name;
|
option = null;
|
||||||
package = cfg.platformTheme.package;
|
name = null;
|
||||||
|
package = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
option = "qt.platformTheme.name";
|
||||||
|
name = cfg.platformTheme.name;
|
||||||
|
package = cfg.platformTheme.package;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Necessary because home.sessionVariables doesn't support mkIf
|
||||||
|
envVars = lib.filterAttrs (n: v: v != null) {
|
||||||
|
QT_QPA_PLATFORMTHEME =
|
||||||
|
if (platformTheme.name != null) then
|
||||||
|
styleNames.${platformTheme.name} or platformTheme.name
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
QT_STYLE_OVERRIDE = cfg.style.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
envVarsExtra =
|
||||||
|
let
|
||||||
|
inherit (config.home) profileDirectory;
|
||||||
|
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;
|
||||||
|
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.");
|
||||||
|
|
||||||
|
qt.style.package = lib.mkIf (cfg.style.name != null) (
|
||||||
|
lib.mkDefault (stylePackages.${lib.toLower cfg.style.name} or null)
|
||||||
|
);
|
||||||
|
|
||||||
|
home = {
|
||||||
|
sessionVariables = envVars;
|
||||||
|
sessionSearchVariables = envVarsExtra;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Apply theming also to apps started by systemd.
|
||||||
|
systemd.user.sessionVariables = envVars // {
|
||||||
|
QT_PLUGIN_PATH = lib.concatStringsSep ":" envVarsExtra.QT_PLUGIN_PATH;
|
||||||
|
QML2_IMPORT_PATH = lib.concatStringsSep ":" envVarsExtra.QML2_IMPORT_PATH;
|
||||||
|
};
|
||||||
|
|
||||||
|
home.packages =
|
||||||
|
(lib.findFirst (x: x != [ ])
|
||||||
|
[ ]
|
||||||
|
[
|
||||||
|
(lib.optionals (platformTheme.package != null) (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"
|
||||||
|
]
|
||||||
|
++ lib.optionals (platformTheme.name != null) [ "QT_QPA_PLATFORMTHEME" ]
|
||||||
|
++ lib.optionals (cfg.style.name != null) [ "QT_STYLE_OVERRIDE" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Necessary because home.sessionVariables doesn't support mkIf
|
|
||||||
envVars = lib.filterAttrs (n: v: v != null) {
|
|
||||||
QT_QPA_PLATFORMTHEME = if (platformTheme.name != null) then
|
|
||||||
styleNames.${platformTheme.name} or platformTheme.name
|
|
||||||
else
|
|
||||||
null;
|
|
||||||
QT_STYLE_OVERRIDE = cfg.style.name;
|
|
||||||
};
|
|
||||||
|
|
||||||
envVarsExtra = let
|
|
||||||
inherit (config.home) profileDirectory;
|
|
||||||
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;
|
|
||||||
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.");
|
|
||||||
|
|
||||||
qt.style.package = lib.mkIf (cfg.style.name != null)
|
|
||||||
(lib.mkDefault (stylePackages.${lib.toLower cfg.style.name} or null));
|
|
||||||
|
|
||||||
home = {
|
|
||||||
sessionVariables = envVars;
|
|
||||||
sessionSearchVariables = envVarsExtra;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Apply theming also to apps started by systemd.
|
|
||||||
systemd.user.sessionVariables = envVars // {
|
|
||||||
QT_PLUGIN_PATH = lib.concatStringsSep ":" envVarsExtra.QT_PLUGIN_PATH;
|
|
||||||
QML2_IMPORT_PATH = lib.concatStringsSep ":" envVarsExtra.QML2_IMPORT_PATH;
|
|
||||||
};
|
|
||||||
|
|
||||||
home.packages = (lib.findFirst (x: x != [ ]) [ ] [
|
|
||||||
(lib.optionals (platformTheme.package != null)
|
|
||||||
(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" ]
|
|
||||||
++ lib.optionals (platformTheme.name != null) [ "QT_QPA_PLATFORMTHEME" ]
|
|
||||||
++ lib.optionals (cfg.style.name != null) [ "QT_STYLE_OVERRIDE" ];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,33 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.qt.kde.settings;
|
cfg = config.qt.kde.settings;
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options.qt.kde.settings = lib.mkOption {
|
options.qt.kde.settings = lib.mkOption {
|
||||||
type = with lib.types;
|
type =
|
||||||
|
with lib.types;
|
||||||
let
|
let
|
||||||
valueType =
|
valueType =
|
||||||
nullOr (oneOf [ bool int float str path (attrsOf valueType) ]) // {
|
nullOr (oneOf [
|
||||||
|
bool
|
||||||
|
int
|
||||||
|
float
|
||||||
|
str
|
||||||
|
path
|
||||||
|
(attrsOf valueType)
|
||||||
|
])
|
||||||
|
// {
|
||||||
description = "KDE option value";
|
description = "KDE option value";
|
||||||
};
|
};
|
||||||
in attrsOf valueType;
|
in
|
||||||
|
attrsOf valueType;
|
||||||
default = { };
|
default = { };
|
||||||
example = {
|
example = {
|
||||||
powermanagementprofilesrc.AC.HandleButtonEvents.lidAction = 32;
|
powermanagementprofilesrc.AC.HandleButtonEvents.lidAction = 32;
|
||||||
|
|
@ -38,28 +54,32 @@ in {
|
||||||
|
|
||||||
config = lib.mkIf (cfg != { }) {
|
config = lib.mkIf (cfg != { }) {
|
||||||
home.activation.kconfig = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
home.activation.kconfig = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
${let
|
${
|
||||||
inherit (config.xdg) configHome;
|
let
|
||||||
toValue = v:
|
inherit (config.xdg) configHome;
|
||||||
let t = builtins.typeOf v;
|
toValue =
|
||||||
in if v == null then
|
v:
|
||||||
"--delete"
|
let
|
||||||
else if t == "bool" then
|
t = builtins.typeOf v;
|
||||||
"--type bool ${builtins.toJSON v}"
|
in
|
||||||
else
|
if v == null then
|
||||||
lib.escapeShellArg (toString v);
|
"--delete"
|
||||||
toLine = file: path: value:
|
else if t == "bool" then
|
||||||
if builtins.isAttrs value then
|
"--type bool ${builtins.toJSON v}"
|
||||||
lib.mapAttrsToList
|
else
|
||||||
(group: value: toLine file (path ++ [ group ]) value) value
|
lib.escapeShellArg (toString v);
|
||||||
else
|
toLine =
|
||||||
"run ${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file '${configHome}/${file}' ${
|
file: path: value:
|
||||||
lib.concatMapStringsSep " " (x: "--group ${x}")
|
if builtins.isAttrs value then
|
||||||
(lib.lists.init path)
|
lib.mapAttrsToList (group: value: toLine file (path ++ [ group ]) value) value
|
||||||
} --key '${lib.lists.last path}' ${toValue value}";
|
else
|
||||||
lines = lib.flatten
|
"run ${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file '${configHome}/${file}' ${
|
||||||
(lib.mapAttrsToList (file: attrs: toLine file [ ] attrs) cfg);
|
lib.concatMapStringsSep " " (x: "--group ${x}") (lib.lists.init path)
|
||||||
in builtins.concatStringsSep "\n" lines}
|
} --key '${lib.lists.last path}' ${toValue value}";
|
||||||
|
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
|
# TODO: some way to only call the dbus calls needed
|
||||||
run ${pkgs.kdePackages.qttools}/bin/qdbus org.kde.KWin /KWin reconfigure || echo "KWin reconfigure failed"
|
run ${pkgs.kdePackages.qttools}/bin/qdbus org.kde.KWin /KWin reconfigure || echo "KWin reconfigure failed"
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,47 @@
|
||||||
{ config, name, extendModules, lib, ... }:
|
{
|
||||||
|
config,
|
||||||
|
name,
|
||||||
|
extendModules,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
imports =
|
imports = [ (lib.mkRenamedOptionModule [ "specialization" ] [ "specialisation" ]) ];
|
||||||
[ (lib.mkRenamedOptionModule [ "specialization" ] [ "specialisation" ]) ];
|
|
||||||
|
|
||||||
options.specialisation = lib.mkOption {
|
options.specialisation = lib.mkOption {
|
||||||
type = lib.types.attrsOf (lib.types.submodule {
|
type = lib.types.attrsOf (
|
||||||
options = {
|
lib.types.submodule {
|
||||||
configuration = lib.mkOption {
|
options = {
|
||||||
type = let
|
configuration = lib.mkOption {
|
||||||
extended = extendModules {
|
type =
|
||||||
modules = [{
|
let
|
||||||
# Prevent infinite recursion
|
extended = extendModules {
|
||||||
specialisation = lib.mkOverride 0 { };
|
modules = [
|
||||||
|
{
|
||||||
|
# Prevent infinite recursion
|
||||||
|
specialisation = lib.mkOverride 0 { };
|
||||||
|
|
||||||
# If used inside the NixOS/nix-darwin module, we get conflicting definitions
|
# If used inside the NixOS/nix-darwin module, we get conflicting definitions
|
||||||
# of `name` inside the specialisation: one is the user name coming from the
|
# of `name` inside the specialisation: one is the user name coming from the
|
||||||
# NixOS module definition and the other is `configuration`, the name of this
|
# NixOS module definition and the other is `configuration`, the name of this
|
||||||
# option. Thus we need to explicitly wire the former into the module arguments.
|
# option. Thus we need to explicitly wire the former into the module arguments.
|
||||||
# See discussion at https://github.com/nix-community/home-manager/issues/3716
|
# See discussion at https://github.com/nix-community/home-manager/issues/3716
|
||||||
_module.args.name = lib.mkForce name;
|
_module.args.name = lib.mkForce name;
|
||||||
}];
|
}
|
||||||
};
|
];
|
||||||
in extended.type;
|
};
|
||||||
default = { };
|
in
|
||||||
visible = "shallow";
|
extended.type;
|
||||||
description = ''
|
default = { };
|
||||||
Arbitrary Home Manager configuration settings.
|
visible = "shallow";
|
||||||
'';
|
description = ''
|
||||||
|
Arbitrary Home Manager configuration settings.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
});
|
);
|
||||||
default = { };
|
default = { };
|
||||||
description = ''
|
description = ''
|
||||||
A set of named specialized configurations. These can be used to extend
|
A set of named specialized configurations. These can be used to extend
|
||||||
|
|
@ -71,18 +82,21 @@
|
||||||
config = lib.mkIf (config.specialisation != { }) {
|
config = lib.mkIf (config.specialisation != { }) {
|
||||||
assertions = map (n: {
|
assertions = map (n: {
|
||||||
assertion = !lib.hasInfix "/" n;
|
assertion = !lib.hasInfix "/" n;
|
||||||
message =
|
message = "<name> in specialisation.<name> cannot contain a forward slash.";
|
||||||
"<name> in specialisation.<name> cannot contain a forward slash.";
|
|
||||||
}) (lib.attrNames config.specialisation);
|
}) (lib.attrNames config.specialisation);
|
||||||
|
|
||||||
home.extraBuilderCommands = let
|
home.extraBuilderCommands =
|
||||||
link = n: v:
|
let
|
||||||
let pkg = v.configuration.home.activationPackage;
|
link =
|
||||||
in "ln -s ${pkg} $out/specialisation/${lib.escapeShellArg n}";
|
n: v:
|
||||||
in ''
|
let
|
||||||
mkdir $out/specialisation
|
pkg = v.configuration.home.activationPackage;
|
||||||
${lib.concatStringsSep "\n"
|
in
|
||||||
(lib.mapAttrsToList link config.specialisation)}
|
"ln -s ${pkg} $out/specialisation/${lib.escapeShellArg n}";
|
||||||
'';
|
in
|
||||||
|
''
|
||||||
|
mkdir $out/specialisation
|
||||||
|
${lib.concatStringsSep "\n" (lib.mapAttrsToList link config.specialisation)}
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.systemd.user.tmpfiles;
|
cfg = config.systemd.user.tmpfiles;
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.dawidsowa ];
|
meta.maintainers = [ lib.maintainers.dawidsowa ];
|
||||||
|
|
||||||
options.systemd.user.tmpfiles.rules = lib.mkOption {
|
options.systemd.user.tmpfiles.rules = lib.mkOption {
|
||||||
|
|
@ -21,8 +27,7 @@ in {
|
||||||
|
|
||||||
config = lib.mkIf (cfg.rules != [ ]) {
|
config = lib.mkIf (cfg.rules != [ ]) {
|
||||||
assertions = [
|
assertions = [
|
||||||
(lib.hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs
|
(lib.hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs lib.platforms.linux)
|
||||||
lib.platforms.linux)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
xdg.configFile = {
|
xdg.configFile = {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ let
|
||||||
|
|
||||||
inherit (lib) mkIf mkOption types;
|
inherit (lib) mkIf mkOption types;
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options.uninstall = mkOption {
|
options.uninstall = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
|
@ -26,25 +27,24 @@ in {
|
||||||
manual.manpages.enable = lib.mkForce false;
|
manual.manpages.enable = lib.mkForce false;
|
||||||
news.display = lib.mkForce "silent";
|
news.display = lib.mkForce "silent";
|
||||||
|
|
||||||
home.activation.uninstall =
|
home.activation.uninstall = lib.hm.dag.entryAfter [ "installPackages" "linkGeneration" ] ''
|
||||||
lib.hm.dag.entryAfter [ "installPackages" "linkGeneration" ] ''
|
nixProfileRemove home-manager-path
|
||||||
nixProfileRemove home-manager-path
|
|
||||||
|
|
||||||
if [[ -e $hmDataPath ]]; then
|
if [[ -e $hmDataPath ]]; then
|
||||||
run rm $VERBOSE_ARG -r "$hmDataPath"
|
run rm $VERBOSE_ARG -r "$hmDataPath"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -e $hmStatePath ]]; then
|
if [[ -e $hmStatePath ]]; then
|
||||||
run rm $VERBOSE_ARG -r "$hmStatePath"
|
run rm $VERBOSE_ARG -r "$hmStatePath"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -e $genProfilePath ]]; then
|
if [[ -e $genProfilePath ]]; then
|
||||||
run rm $VERBOSE_ARG "$genProfilePath"*
|
run rm $VERBOSE_ARG "$genProfilePath"*
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -e $legacyGenGcPath ]]; then
|
if [[ -e $legacyGenGcPath ]]; then
|
||||||
run rm $VERBOSE_ARG "$legacyGenGcPath"
|
run rm $VERBOSE_ARG "$legacyGenGcPath"
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@ let
|
||||||
|
|
||||||
releaseInfo = lib.importJSON ../../release.json;
|
releaseInfo = lib.importJSON ../../release.json;
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
home.stateVersion = lib.mkOption {
|
home.stateVersion = lib.mkOption {
|
||||||
type = types.enum [
|
type = types.enum [
|
||||||
|
|
@ -44,11 +45,12 @@ in {
|
||||||
internal = true;
|
internal = true;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = let
|
default =
|
||||||
inherit (config.home.version) release revision;
|
let
|
||||||
suffix = lib.optionalString (revision != null)
|
inherit (config.home.version) release revision;
|
||||||
"+${lib.substring 0 8 revision}";
|
suffix = lib.optionalString (revision != null) "+${lib.substring 0 8 revision}";
|
||||||
in "${release}${suffix}";
|
in
|
||||||
|
"${release}${suffix}";
|
||||||
example = "22.11+213a0629";
|
example = "22.11+213a0629";
|
||||||
description = "The full Home Manager version.";
|
description = "The full Home Manager version.";
|
||||||
};
|
};
|
||||||
|
|
@ -76,11 +78,11 @@ in {
|
||||||
revision = lib.mkOption {
|
revision = lib.mkOption {
|
||||||
internal = true;
|
internal = true;
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = let gitRepo = "${toString ./../..}/.git";
|
default =
|
||||||
in if lib.pathIsGitRepo gitRepo then
|
let
|
||||||
lib.commitIdFromGitRepo gitRepo
|
gitRepo = "${toString ./../..}/.git";
|
||||||
else
|
in
|
||||||
null;
|
if lib.pathIsGitRepo gitRepo then lib.commitIdFromGitRepo gitRepo else null;
|
||||||
description = ''
|
description = ''
|
||||||
The Git revision from which this Home Manager configuration was built.
|
The Git revision from which this Home Manager configuration was built.
|
||||||
'';
|
'';
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,30 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
meta.maintainers = [ lib.maintainers.rycee ];
|
meta.maintainers = [ lib.maintainers.rycee ];
|
||||||
|
|
||||||
options.programs = let
|
options.programs =
|
||||||
description = ''
|
let
|
||||||
Whether to enable integration with terminals using the VTE
|
description = ''
|
||||||
library. This will let the terminal track the current working
|
Whether to enable integration with terminals using the VTE
|
||||||
directory.
|
library. This will let the terminal track the current working
|
||||||
'';
|
directory.
|
||||||
in {
|
'';
|
||||||
bash.enableVteIntegration = lib.mkEnableOption "" // {
|
in
|
||||||
inherit description;
|
{
|
||||||
};
|
bash.enableVteIntegration = lib.mkEnableOption "" // {
|
||||||
|
inherit description;
|
||||||
|
};
|
||||||
|
|
||||||
zsh.enableVteIntegration = lib.mkEnableOption "" // {
|
zsh.enableVteIntegration = lib.mkEnableOption "" // {
|
||||||
inherit description;
|
inherit description;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
(lib.mkIf config.programs.bash.enableVteIntegration {
|
(lib.mkIf config.programs.bash.enableVteIntegration {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,23 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (builtins) baseNameOf listToAttrs map unsafeDiscardStringContext;
|
inherit (builtins)
|
||||||
inherit (lib) literalExpression mkEnableOption mkIf mkOption types;
|
baseNameOf
|
||||||
|
listToAttrs
|
||||||
|
map
|
||||||
|
unsafeDiscardStringContext
|
||||||
|
;
|
||||||
|
inherit (lib)
|
||||||
|
literalExpression
|
||||||
|
mkEnableOption
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.xdg.autostart;
|
cfg = config.xdg.autostart;
|
||||||
|
|
||||||
|
|
@ -10,7 +26,8 @@ let
|
||||||
${lib.concatMapStringsSep "\n" (e: "ln -s ${e} $out") cfg.entries}
|
${lib.concatMapStringsSep "\n" (e: "ln -s ${e} $out") cfg.entries}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = with lib.maintainers; [ Scrumplex ];
|
meta.maintainers = with lib.maintainers; [ Scrumplex ];
|
||||||
|
|
||||||
options.xdg.autostart = {
|
options.xdg.autostart = {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) literalExpression mkOption types;
|
inherit (lib) literalExpression mkOption types;
|
||||||
|
|
@ -6,9 +11,9 @@ let
|
||||||
desktopEntry = {
|
desktopEntry = {
|
||||||
imports = [
|
imports = [
|
||||||
(lib.mkRemovedOptionModule [ "extraConfig" ]
|
(lib.mkRemovedOptionModule [ "extraConfig" ]
|
||||||
"The `extraConfig` option of `xdg.desktopEntries` has been removed following a change in Nixpkgs.")
|
"The `extraConfig` option of `xdg.desktopEntries` has been removed following a change in Nixpkgs."
|
||||||
(lib.mkRemovedOptionModule [ "fileValidation" ]
|
)
|
||||||
"Validation of the desktop file is always enabled.")
|
(lib.mkRemovedOptionModule [ "fileValidation" ] "Validation of the desktop file is always enabled.")
|
||||||
];
|
];
|
||||||
options = {
|
options = {
|
||||||
# Since this module uses the nixpkgs/pkgs/build-support/make-desktopitem function,
|
# Since this module uses the nixpkgs/pkgs/build-support/make-desktopitem function,
|
||||||
|
|
@ -28,7 +33,11 @@ let
|
||||||
type = mkOption {
|
type = mkOption {
|
||||||
description = "The type of the desktop entry.";
|
description = "The type of the desktop entry.";
|
||||||
default = "Application";
|
default = "Application";
|
||||||
type = types.enum [ "Application" "Link" "Directory" ];
|
type = types.enum [
|
||||||
|
"Application"
|
||||||
|
"Link"
|
||||||
|
"Directory"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
exec = mkOption {
|
exec = mkOption {
|
||||||
|
|
@ -73,8 +82,7 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
categories = mkOption {
|
categories = mkOption {
|
||||||
description =
|
description = "Categories in which the entry should be shown in a menu.";
|
||||||
"Categories in which the entry should be shown in a menu.";
|
|
||||||
type = types.nullOr (types.listOf types.str);
|
type = types.nullOr (types.listOf types.str);
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
@ -122,24 +130,29 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
actions = mkOption {
|
actions = mkOption {
|
||||||
type = types.attrsOf (types.submodule ({ name, ... }: {
|
type = types.attrsOf (
|
||||||
options.name = mkOption {
|
types.submodule (
|
||||||
type = types.str;
|
{ name, ... }:
|
||||||
default = name;
|
{
|
||||||
defaultText = literalExpression "<name>";
|
options.name = mkOption {
|
||||||
description = "Name of the action.";
|
type = types.str;
|
||||||
};
|
default = name;
|
||||||
options.exec = mkOption {
|
defaultText = literalExpression "<name>";
|
||||||
type = types.nullOr types.str;
|
description = "Name of the action.";
|
||||||
description = "Program to execute, possibly with arguments.";
|
};
|
||||||
default = null;
|
options.exec = mkOption {
|
||||||
};
|
type = types.nullOr types.str;
|
||||||
options.icon = mkOption {
|
description = "Program to execute, possibly with arguments.";
|
||||||
type = with types; nullOr (either str path);
|
default = null;
|
||||||
default = null;
|
};
|
||||||
description = "Icon to display in file manager, menus, etc.";
|
options.icon = mkOption {
|
||||||
};
|
type = with types; nullOr (either str path);
|
||||||
}));
|
default = null;
|
||||||
|
description = "Icon to display in file manager, menus, etc.";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
default = { };
|
default = { };
|
||||||
defaultText = literalExpression "{ }";
|
defaultText = literalExpression "{ }";
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
|
|
@ -149,8 +162,7 @@ let
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
description =
|
description = "The set of actions made available to application launchers.";
|
||||||
"The set of actions made available to application launchers.";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Required for the assertions
|
# Required for the assertions
|
||||||
|
|
@ -165,18 +177,29 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
#passes config options to makeDesktopItem in expected format
|
#passes config options to makeDesktopItem in expected format
|
||||||
makeFile = name: config:
|
makeFile =
|
||||||
|
name: config:
|
||||||
pkgs.makeDesktopItem {
|
pkgs.makeDesktopItem {
|
||||||
inherit name;
|
inherit name;
|
||||||
inherit (config)
|
inherit (config)
|
||||||
type exec icon comment terminal genericName startupNotify noDisplay
|
type
|
||||||
prefersNonDefaultGPU actions;
|
exec
|
||||||
|
icon
|
||||||
|
comment
|
||||||
|
terminal
|
||||||
|
genericName
|
||||||
|
startupNotify
|
||||||
|
noDisplay
|
||||||
|
prefersNonDefaultGPU
|
||||||
|
actions
|
||||||
|
;
|
||||||
desktopName = config.name;
|
desktopName = config.name;
|
||||||
mimeTypes = lib.optionals (config.mimeType != null) config.mimeType;
|
mimeTypes = lib.optionals (config.mimeType != null) config.mimeType;
|
||||||
categories = lib.optionals (config.categories != null) config.categories;
|
categories = lib.optionals (config.categories != null) config.categories;
|
||||||
extraConfig = config.settings;
|
extraConfig = config.settings;
|
||||||
};
|
};
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.hm.maintainers.cwyc ];
|
meta.maintainers = [ lib.hm.maintainers.cwyc ];
|
||||||
|
|
||||||
options.xdg.desktopEntries = mkOption {
|
options.xdg.desktopEntries = mkOption {
|
||||||
|
|
@ -205,14 +228,13 @@ in {
|
||||||
|
|
||||||
config = lib.mkIf (config.xdg.desktopEntries != { }) {
|
config = lib.mkIf (config.xdg.desktopEntries != { }) {
|
||||||
assertions = [
|
assertions = [
|
||||||
(lib.hm.assertions.assertPlatform "xdg.desktopEntries" pkgs
|
(lib.hm.assertions.assertPlatform "xdg.desktopEntries" pkgs lib.platforms.linux)
|
||||||
lib.platforms.linux)
|
] ++ lib.flatten (lib.catAttrs "assertions" (lib.attrValues config.xdg.desktopEntries));
|
||||||
] ++ lib.flatten
|
|
||||||
(lib.catAttrs "assertions" (lib.attrValues config.xdg.desktopEntries));
|
|
||||||
|
|
||||||
home.packages =
|
home.packages = (
|
||||||
(map lib.hiPrio # we need hiPrio to override existing entries
|
map lib.hiPrio # we need hiPrio to override existing entries
|
||||||
(lib.attrsets.mapAttrsToList makeFile config.xdg.desktopEntries));
|
(lib.attrsets.mapAttrsToList makeFile config.xdg.desktopEntries)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types;
|
||||||
|
|
||||||
cfg = config.xdg.mimeApps;
|
cfg = config.xdg.mimeApps;
|
||||||
|
|
||||||
strListOrSingleton = with types;
|
strListOrSingleton = with types; coercedTo (either (listOf str) str) lib.toList (listOf str);
|
||||||
coercedTo (either (listOf str) str) lib.toList (listOf str);
|
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = with lib.maintainers; [ euxane ];
|
meta.maintainers = with lib.maintainers; [ euxane ];
|
||||||
|
|
||||||
options.xdg.mimeApps = {
|
options.xdg.mimeApps = {
|
||||||
|
|
@ -44,7 +49,9 @@ in {
|
||||||
associations.removed = mkOption {
|
associations.removed = mkOption {
|
||||||
type = types.attrsOf strListOrSingleton;
|
type = types.attrsOf strListOrSingleton;
|
||||||
default = { };
|
default = { };
|
||||||
example = { "mimetype1" = "foo5.desktop"; };
|
example = {
|
||||||
|
"mimetype1" = "foo5.desktop";
|
||||||
|
};
|
||||||
description = ''
|
description = ''
|
||||||
Removes associations of applications with mimetypes, as if the
|
Removes associations of applications with mimetypes, as if the
|
||||||
.desktop file was *not* listing this
|
.desktop file was *not* listing this
|
||||||
|
|
@ -75,43 +82,47 @@ in {
|
||||||
# Given a package that installs .desktop files in the usual location,
|
# Given a package that installs .desktop files in the usual location,
|
||||||
# return a mapping from mime types to lists of desktop file names. This is
|
# return a mapping from mime types to lists of desktop file names. This is
|
||||||
# suitable for use with `xdg.mimeApps.defaultApplications`.
|
# suitable for use with `xdg.mimeApps.defaultApplications`.
|
||||||
lib.xdg.mimeAssociations = let
|
lib.xdg.mimeAssociations =
|
||||||
processLines = str:
|
let
|
||||||
lib.zipAttrs (lib.filter (e: e != null)
|
processLines =
|
||||||
(map processLine (lib.splitString "\n" str)));
|
str: lib.zipAttrs (lib.filter (e: e != null) (map processLine (lib.splitString "\n" str)));
|
||||||
|
|
||||||
processLine = str:
|
processLine =
|
||||||
let
|
str:
|
||||||
entry = lib.splitString ";" str;
|
let
|
||||||
k = lib.elemAt entry 0;
|
entry = lib.splitString ";" str;
|
||||||
v = lib.elemAt entry 1;
|
k = lib.elemAt entry 0;
|
||||||
in if lib.length entry == 2 then { ${k} = v; } else null;
|
v = lib.elemAt entry 1;
|
||||||
|
in
|
||||||
|
if lib.length entry == 2 then { ${k} = v; } else null;
|
||||||
|
|
||||||
associations = ps:
|
associations =
|
||||||
pkgs.runCommand "mime-assoc" { inherit ps; } ''
|
ps:
|
||||||
for p in $ps ; do
|
pkgs.runCommand "mime-assoc" { inherit ps; } ''
|
||||||
for path in "$p"/share/applications/*.desktop ; do
|
for p in $ps ; do
|
||||||
name="''${path##*/}"
|
for path in "$p"/share/applications/*.desktop ; do
|
||||||
sed -n -E "/^MimeType=/ { s/.*=//; s/;?$|;/;$name\n/g; p; }" "$path"
|
name="''${path##*/}"
|
||||||
done
|
sed -n -E "/^MimeType=/ { s/.*=//; s/;?$|;/;$name\n/g; p; }" "$path"
|
||||||
done > "$out"
|
done
|
||||||
'';
|
done > "$out"
|
||||||
in p: processLines (builtins.readFile (associations p));
|
'';
|
||||||
|
in
|
||||||
|
p: processLines (builtins.readFile (associations p));
|
||||||
}
|
}
|
||||||
|
|
||||||
(lib.mkIf cfg.enable {
|
(lib.mkIf cfg.enable {
|
||||||
assertions = [
|
assertions = [
|
||||||
(lib.hm.assertions.assertPlatform "xdg.mimeApps" pkgs
|
(lib.hm.assertions.assertPlatform "xdg.mimeApps" pkgs lib.platforms.linux)
|
||||||
lib.platforms.linux)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
# Deprecated but still used by some applications.
|
# Deprecated but still used by some applications.
|
||||||
xdg.dataFile."applications/mimeapps.list".source =
|
xdg.dataFile."applications/mimeapps.list".source = config.xdg.configFile."mimeapps.list".source;
|
||||||
config.xdg.configFile."mimeapps.list".source;
|
|
||||||
|
|
||||||
xdg.configFile."mimeapps.list".text =
|
xdg.configFile."mimeapps.list".text =
|
||||||
let joinValues = lib.mapAttrs (n: lib.concatStringsSep ";");
|
let
|
||||||
in lib.generators.toINI { } {
|
joinValues = lib.mapAttrs (n: lib.concatStringsSep ";");
|
||||||
|
in
|
||||||
|
lib.generators.toINI { } {
|
||||||
"Added Associations" = joinValues cfg.associations.added;
|
"Added Associations" = joinValues cfg.associations.added;
|
||||||
"Removed Associations" = joinValues cfg.associations.removed;
|
"Removed Associations" = joinValues cfg.associations.removed;
|
||||||
"Default Applications" = joinValues cfg.defaultApplications;
|
"Default Applications" = joinValues cfg.defaultApplications;
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,29 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.xdg.mime;
|
cfg = config.xdg.mime;
|
||||||
|
|
||||||
inherit (lib) getExe getExe' mkOption types;
|
inherit (lib)
|
||||||
|
getExe
|
||||||
|
getExe'
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
xdg.mime = {
|
xdg.mime = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = pkgs.stdenv.hostPlatform.isLinux;
|
default = pkgs.stdenv.hostPlatform.isLinux;
|
||||||
defaultText = lib.literalExpression
|
defaultText = lib.literalExpression "true if host platform is Linux, false otherwise";
|
||||||
"true if host platform is Linux, false otherwise";
|
|
||||||
description = ''
|
description = ''
|
||||||
Whether to install programs and files to support the
|
Whether to install programs and files to support the
|
||||||
XDG Shared MIME-info specification and XDG MIME Applications
|
XDG Shared MIME-info specification and XDG MIME Applications
|
||||||
|
|
@ -36,8 +46,7 @@ in {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = pkgs.desktop-file-utils;
|
default = pkgs.desktop-file-utils;
|
||||||
defaultText = lib.literalExpression "pkgs.desktop-file-utils";
|
defaultText = lib.literalExpression "pkgs.desktop-file-utils";
|
||||||
description =
|
description = "The package to use when running update-desktop-database.";
|
||||||
"The package to use when running update-desktop-database.";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -64,16 +73,14 @@ in {
|
||||||
XDG_DATA_DIRS=$out/share \
|
XDG_DATA_DIRS=$out/share \
|
||||||
PKGSYSTEM_ENABLE_FSYNC=0 \
|
PKGSYSTEM_ENABLE_FSYNC=0 \
|
||||||
${
|
${
|
||||||
getExe
|
getExe (cfg.sharedMimeInfoPackage.__spliced.buildHost or cfg.sharedMimeInfoPackage)
|
||||||
(cfg.sharedMimeInfoPackage.__spliced.buildHost or cfg.sharedMimeInfoPackage)
|
|
||||||
} -V $out/share/mime > /dev/null
|
} -V $out/share/mime > /dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -w $out/share/applications ]]; then
|
if [[ -w $out/share/applications ]]; then
|
||||||
${
|
${
|
||||||
getExe'
|
getExe' (cfg.desktopFileUtilsPackage.__spliced.buildHost or cfg.desktopFileUtilsPackage
|
||||||
(cfg.desktopFileUtilsPackage.__spliced.buildHost or cfg.desktopFileUtilsPackage)
|
) "update-desktop-database"
|
||||||
"update-desktop-database"
|
|
||||||
} $out/share/applications
|
} $out/share/applications
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,26 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
inherit (lib) mkIf mkMerge mkOption optional types;
|
inherit (lib)
|
||||||
|
mkIf
|
||||||
|
mkMerge
|
||||||
|
mkOption
|
||||||
|
optional
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
associationOptions = with types;
|
associationOptions =
|
||||||
attrsOf (coercedTo (either (listOf str) str)
|
with types;
|
||||||
(x: lib.concatStringsSep ";" (lib.toList x)) str);
|
attrsOf (coercedTo (either (listOf str) str) (x: lib.concatStringsSep ";" (lib.toList x)) str);
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.misterio77 ];
|
meta.maintainers = [ lib.maintainers.misterio77 ];
|
||||||
|
|
||||||
options.xdg.portal = {
|
options.xdg.portal = {
|
||||||
|
|
@ -63,12 +75,22 @@ in {
|
||||||
type = types.attrsOf associationOptions;
|
type = types.attrsOf associationOptions;
|
||||||
default = { };
|
default = { };
|
||||||
example = {
|
example = {
|
||||||
x-cinnamon = { default = [ "xapp" "gtk" ]; };
|
x-cinnamon = {
|
||||||
|
default = [
|
||||||
|
"xapp"
|
||||||
|
"gtk"
|
||||||
|
];
|
||||||
|
};
|
||||||
pantheon = {
|
pantheon = {
|
||||||
default = [ "pantheon" "gtk" ];
|
default = [
|
||||||
|
"pantheon"
|
||||||
|
"gtk"
|
||||||
|
];
|
||||||
"org.freedesktop.impl.portal.Secret" = [ "gnome-keyring" ];
|
"org.freedesktop.impl.portal.Secret" = [ "gnome-keyring" ];
|
||||||
};
|
};
|
||||||
common = { default = [ "gtk" ]; };
|
common = {
|
||||||
|
default = [ "gtk" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
description = ''
|
description = ''
|
||||||
Sets which portal backend should be used to provide the implementation
|
Sets which portal backend should be used to provide the implementation
|
||||||
|
|
@ -97,51 +119,53 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let
|
config =
|
||||||
cfg = config.xdg.portal;
|
let
|
||||||
packages = [ pkgs.xdg-desktop-portal ] ++ cfg.extraPortals;
|
cfg = config.xdg.portal;
|
||||||
portalsDir =
|
packages = [ pkgs.xdg-desktop-portal ] ++ cfg.extraPortals;
|
||||||
"${config.home.profileDirectory}/share/xdg-desktop-portal/portals";
|
portalsDir = "${config.home.profileDirectory}/share/xdg-desktop-portal/portals";
|
||||||
in mkIf cfg.enable {
|
in
|
||||||
warnings = optional (cfg.configPackages == [ ] && cfg.config == { }) ''
|
mkIf cfg.enable {
|
||||||
xdg-desktop-portal 1.17 reworked how portal implementations are loaded, you
|
warnings = optional (cfg.configPackages == [ ] && cfg.config == { }) ''
|
||||||
should either set `xdg.portal.config` or `xdg.portal.configPackages`
|
xdg-desktop-portal 1.17 reworked how portal implementations are loaded, you
|
||||||
to specify which portal backend to use for the requested interface.
|
should either set `xdg.portal.config` or `xdg.portal.configPackages`
|
||||||
|
to specify which portal backend to use for the requested interface.
|
||||||
|
|
||||||
https://github.com/flatpak/xdg-desktop-portal/blob/1.18.1/doc/portals.conf.rst.in
|
https://github.com/flatpak/xdg-desktop-portal/blob/1.18.1/doc/portals.conf.rst.in
|
||||||
|
|
||||||
If you simply want to keep the behaviour in < 1.17, which uses the first
|
If you simply want to keep the behaviour in < 1.17, which uses the first
|
||||||
portal implementation found in lexicographical order, use the following:
|
portal implementation found in lexicographical order, use the following:
|
||||||
|
|
||||||
xdg.portal.config.common.default = "*";
|
xdg.portal.config.common.default = "*";
|
||||||
'';
|
'';
|
||||||
|
|
||||||
assertions = [
|
assertions = [
|
||||||
(lib.hm.assertions.assertPlatform "xdg.portal" pkgs lib.platforms.linux)
|
(lib.hm.assertions.assertPlatform "xdg.portal" pkgs lib.platforms.linux)
|
||||||
|
|
||||||
{
|
{
|
||||||
assertion = cfg.extraPortals != [ ];
|
assertion = cfg.extraPortals != [ ];
|
||||||
message =
|
message = "Setting xdg.portal.enable to true requires a portal implementation in xdg.portal.extraPortals such as xdg-desktop-portal-gtk or xdg-desktop-portal-kde.";
|
||||||
"Setting xdg.portal.enable to true requires a portal implementation in xdg.portal.extraPortals such as xdg-desktop-portal-gtk or xdg-desktop-portal-kde.";
|
}
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
home = {
|
|
||||||
packages = packages ++ cfg.configPackages;
|
|
||||||
sessionVariables = mkMerge [
|
|
||||||
(mkIf cfg.xdgOpenUsePortal { NIXOS_XDG_OPEN_USE_PORTAL = "1"; })
|
|
||||||
{ NIX_XDG_DESKTOP_PORTAL_DIR = portalsDir; }
|
|
||||||
];
|
];
|
||||||
};
|
|
||||||
systemd.user.sessionVariables = {
|
|
||||||
NIX_XDG_DESKTOP_PORTAL_DIR = portalsDir;
|
|
||||||
};
|
|
||||||
|
|
||||||
xdg.configFile = lib.concatMapAttrs (desktop: conf:
|
home = {
|
||||||
lib.optionalAttrs (conf != { }) {
|
packages = packages ++ cfg.configPackages;
|
||||||
"xdg-desktop-portal/${
|
sessionVariables = mkMerge [
|
||||||
lib.optionalString (desktop != "common") "${desktop}-"
|
(mkIf cfg.xdgOpenUsePortal { NIXOS_XDG_OPEN_USE_PORTAL = "1"; })
|
||||||
}portals.conf".text = lib.generators.toINI { } { preferred = conf; };
|
{ NIX_XDG_DESKTOP_PORTAL_DIR = portalsDir; }
|
||||||
}) cfg.config;
|
];
|
||||||
};
|
};
|
||||||
|
systemd.user.sessionVariables = {
|
||||||
|
NIX_XDG_DESKTOP_PORTAL_DIR = portalsDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) types;
|
inherit (lib) types;
|
||||||
|
|
@ -9,7 +14,8 @@ let
|
||||||
|
|
||||||
dataDirs = lib.concatStringsSep ":" cfg.data;
|
dataDirs = lib.concatStringsSep ":" cfg.data;
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = with lib.maintainers; [ tadfisher ];
|
meta.maintainers = with lib.maintainers; [ tadfisher ];
|
||||||
|
|
||||||
options.xdg.systemDirs = {
|
options.xdg.systemDirs = {
|
||||||
|
|
@ -37,25 +43,20 @@ in {
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
(lib.mkIf (cfg.config != [ ] || cfg.data != [ ]) {
|
(lib.mkIf (cfg.config != [ ] || cfg.data != [ ]) {
|
||||||
assertions = [
|
assertions = [
|
||||||
(lib.hm.assertions.assertPlatform "xdg.systemDirs" pkgs
|
(lib.hm.assertions.assertPlatform "xdg.systemDirs" pkgs lib.platforms.linux)
|
||||||
lib.platforms.linux)
|
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
|
|
||||||
(lib.mkIf (cfg.config != [ ]) {
|
(lib.mkIf (cfg.config != [ ]) {
|
||||||
home.sessionVariables.XDG_CONFIG_DIRS =
|
home.sessionVariables.XDG_CONFIG_DIRS = "${configDirs}\${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}";
|
||||||
"${configDirs}\${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}";
|
|
||||||
|
|
||||||
systemd.user.sessionVariables.XDG_CONFIG_DIRS =
|
systemd.user.sessionVariables.XDG_CONFIG_DIRS = "${configDirs}\${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}";
|
||||||
"${configDirs}\${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}";
|
|
||||||
})
|
})
|
||||||
|
|
||||||
(lib.mkIf (cfg.data != [ ]) {
|
(lib.mkIf (cfg.data != [ ]) {
|
||||||
home.sessionVariables.XDG_DATA_DIRS =
|
home.sessionVariables.XDG_DATA_DIRS = "${dataDirs}\${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}";
|
||||||
"${dataDirs}\${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}";
|
|
||||||
|
|
||||||
systemd.user.sessionVariables.XDG_DATA_DIRS =
|
systemd.user.sessionVariables.XDG_DATA_DIRS = "${dataDirs}\${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}";
|
||||||
"${dataDirs}\${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}";
|
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,28 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) literalExpression mkOption types;
|
inherit (lib) literalExpression mkOption types;
|
||||||
|
|
||||||
cfg = config.xdg.userDirs;
|
cfg = config.xdg.userDirs;
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = with lib.maintainers; [ euxane ];
|
meta.maintainers = with lib.maintainers; [ euxane ];
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
(lib.mkRenamedOptionModule [ "xdg" "userDirs" "publishShare" ] [
|
(lib.mkRenamedOptionModule
|
||||||
"xdg"
|
[ "xdg" "userDirs" "publishShare" ]
|
||||||
"userDirs"
|
[
|
||||||
"publicShare"
|
"xdg"
|
||||||
])
|
"userDirs"
|
||||||
|
"publicShare"
|
||||||
|
]
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
options.xdg.userDirs = {
|
options.xdg.userDirs = {
|
||||||
|
|
@ -33,64 +42,56 @@ in {
|
||||||
desktop = mkOption {
|
desktop = mkOption {
|
||||||
type = with types; nullOr (coercedTo path toString str);
|
type = with types; nullOr (coercedTo path toString str);
|
||||||
default = "${config.home.homeDirectory}/Desktop";
|
default = "${config.home.homeDirectory}/Desktop";
|
||||||
defaultText =
|
defaultText = literalExpression ''"''${config.home.homeDirectory}/Desktop"'';
|
||||||
literalExpression ''"''${config.home.homeDirectory}/Desktop"'';
|
|
||||||
description = "The Desktop directory.";
|
description = "The Desktop directory.";
|
||||||
};
|
};
|
||||||
|
|
||||||
documents = mkOption {
|
documents = mkOption {
|
||||||
type = with types; nullOr (coercedTo path toString str);
|
type = with types; nullOr (coercedTo path toString str);
|
||||||
default = "${config.home.homeDirectory}/Documents";
|
default = "${config.home.homeDirectory}/Documents";
|
||||||
defaultText =
|
defaultText = literalExpression ''"''${config.home.homeDirectory}/Documents"'';
|
||||||
literalExpression ''"''${config.home.homeDirectory}/Documents"'';
|
|
||||||
description = "The Documents directory.";
|
description = "The Documents directory.";
|
||||||
};
|
};
|
||||||
|
|
||||||
download = mkOption {
|
download = mkOption {
|
||||||
type = with types; nullOr (coercedTo path toString str);
|
type = with types; nullOr (coercedTo path toString str);
|
||||||
default = "${config.home.homeDirectory}/Downloads";
|
default = "${config.home.homeDirectory}/Downloads";
|
||||||
defaultText =
|
defaultText = literalExpression ''"''${config.home.homeDirectory}/Downloads"'';
|
||||||
literalExpression ''"''${config.home.homeDirectory}/Downloads"'';
|
|
||||||
description = "The Downloads directory.";
|
description = "The Downloads directory.";
|
||||||
};
|
};
|
||||||
|
|
||||||
music = mkOption {
|
music = mkOption {
|
||||||
type = with types; nullOr (coercedTo path toString str);
|
type = with types; nullOr (coercedTo path toString str);
|
||||||
default = "${config.home.homeDirectory}/Music";
|
default = "${config.home.homeDirectory}/Music";
|
||||||
defaultText =
|
defaultText = literalExpression ''"''${config.home.homeDirectory}/Music"'';
|
||||||
literalExpression ''"''${config.home.homeDirectory}/Music"'';
|
|
||||||
description = "The Music directory.";
|
description = "The Music directory.";
|
||||||
};
|
};
|
||||||
|
|
||||||
pictures = mkOption {
|
pictures = mkOption {
|
||||||
type = with types; nullOr (coercedTo path toString str);
|
type = with types; nullOr (coercedTo path toString str);
|
||||||
default = "${config.home.homeDirectory}/Pictures";
|
default = "${config.home.homeDirectory}/Pictures";
|
||||||
defaultText =
|
defaultText = literalExpression ''"''${config.home.homeDirectory}/Pictures"'';
|
||||||
literalExpression ''"''${config.home.homeDirectory}/Pictures"'';
|
|
||||||
description = "The Pictures directory.";
|
description = "The Pictures directory.";
|
||||||
};
|
};
|
||||||
|
|
||||||
publicShare = mkOption {
|
publicShare = mkOption {
|
||||||
type = with types; nullOr (coercedTo path toString str);
|
type = with types; nullOr (coercedTo path toString str);
|
||||||
default = "${config.home.homeDirectory}/Public";
|
default = "${config.home.homeDirectory}/Public";
|
||||||
defaultText =
|
defaultText = literalExpression ''"''${config.home.homeDirectory}/Public"'';
|
||||||
literalExpression ''"''${config.home.homeDirectory}/Public"'';
|
|
||||||
description = "The Public share directory.";
|
description = "The Public share directory.";
|
||||||
};
|
};
|
||||||
|
|
||||||
templates = mkOption {
|
templates = mkOption {
|
||||||
type = with types; nullOr (coercedTo path toString str);
|
type = with types; nullOr (coercedTo path toString str);
|
||||||
default = "${config.home.homeDirectory}/Templates";
|
default = "${config.home.homeDirectory}/Templates";
|
||||||
defaultText =
|
defaultText = literalExpression ''"''${config.home.homeDirectory}/Templates"'';
|
||||||
literalExpression ''"''${config.home.homeDirectory}/Templates"'';
|
|
||||||
description = "The Templates directory.";
|
description = "The Templates directory.";
|
||||||
};
|
};
|
||||||
|
|
||||||
videos = mkOption {
|
videos = mkOption {
|
||||||
type = with types; nullOr (coercedTo path toString str);
|
type = with types; nullOr (coercedTo path toString str);
|
||||||
default = "${config.home.homeDirectory}/Videos";
|
default = "${config.home.homeDirectory}/Videos";
|
||||||
defaultText =
|
defaultText = literalExpression ''"''${config.home.homeDirectory}/Videos"'';
|
||||||
literalExpression ''"''${config.home.homeDirectory}/Videos"'';
|
|
||||||
description = "The Videos directory.";
|
description = "The Videos directory.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -106,41 +107,48 @@ in {
|
||||||
description = "Other user directories.";
|
description = "Other user directories.";
|
||||||
};
|
};
|
||||||
|
|
||||||
createDirectories =
|
createDirectories = lib.mkEnableOption "automatic creation of the XDG user directories";
|
||||||
lib.mkEnableOption "automatic creation of the XDG user directories";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let
|
config =
|
||||||
directories = (lib.filterAttrs (n: v: !isNull v) {
|
let
|
||||||
XDG_DESKTOP_DIR = cfg.desktop;
|
directories =
|
||||||
XDG_DOCUMENTS_DIR = cfg.documents;
|
(lib.filterAttrs (n: v: !isNull v) {
|
||||||
XDG_DOWNLOAD_DIR = cfg.download;
|
XDG_DESKTOP_DIR = cfg.desktop;
|
||||||
XDG_MUSIC_DIR = cfg.music;
|
XDG_DOCUMENTS_DIR = cfg.documents;
|
||||||
XDG_PICTURES_DIR = cfg.pictures;
|
XDG_DOWNLOAD_DIR = cfg.download;
|
||||||
XDG_PUBLICSHARE_DIR = cfg.publicShare;
|
XDG_MUSIC_DIR = cfg.music;
|
||||||
XDG_TEMPLATES_DIR = cfg.templates;
|
XDG_PICTURES_DIR = cfg.pictures;
|
||||||
XDG_VIDEOS_DIR = cfg.videos;
|
XDG_PUBLICSHARE_DIR = cfg.publicShare;
|
||||||
}) // cfg.extraConfig;
|
XDG_TEMPLATES_DIR = cfg.templates;
|
||||||
in lib.mkIf cfg.enable {
|
XDG_VIDEOS_DIR = cfg.videos;
|
||||||
assertions = [
|
})
|
||||||
(lib.hm.assertions.assertPlatform "xdg.userDirs" pkgs lib.platforms.linux)
|
// 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 =
|
||||||
# For some reason, these need to be wrapped with quotes to be valid.
|
let
|
||||||
wrapped = lib.mapAttrs (_: value: ''"${value}"'') directories;
|
# For some reason, these need to be wrapped with quotes to be valid.
|
||||||
in lib.generators.toKeyValue { } wrapped;
|
wrapped = lib.mapAttrs (_: value: ''"${value}"'') directories;
|
||||||
|
in
|
||||||
|
lib.generators.toKeyValue { } wrapped;
|
||||||
|
|
||||||
xdg.configFile."user-dirs.conf".text = "enabled=False";
|
xdg.configFile."user-dirs.conf".text = "enabled=False";
|
||||||
|
|
||||||
home.sessionVariables = directories;
|
home.sessionVariables = directories;
|
||||||
|
|
||||||
home.activation.createXdgUserDirectories = lib.mkIf cfg.createDirectories
|
home.activation.createXdgUserDirectories = lib.mkIf cfg.createDirectories (
|
||||||
(let
|
let
|
||||||
directoriesList = lib.attrValues directories;
|
directoriesList = lib.attrValues directories;
|
||||||
mkdir =
|
mkdir = (dir: ''[[ -L "${dir}" ]] || run mkdir -p $VERBOSE_ARG "${dir}"'');
|
||||||
(dir: ''[[ -L "${dir}" ]] || run mkdir -p $VERBOSE_ARG "${dir}"'');
|
in
|
||||||
in lib.hm.dag.entryAfter [ "linkGeneration" ]
|
lib.hm.dag.entryAfter [ "linkGeneration" ] (
|
||||||
(lib.strings.concatMapStringsSep "\n" mkdir directoriesList));
|
lib.strings.concatMapStringsSep "\n" mkdir directoriesList
|
||||||
};
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,40 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) mkOptionDefault mkIf mkOption types;
|
inherit (lib)
|
||||||
|
mkOptionDefault
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.xdg;
|
cfg = config.xdg;
|
||||||
|
|
||||||
fileType = (import ../lib/file-type.nix {
|
fileType =
|
||||||
inherit (config.home) homeDirectory;
|
(import ../lib/file-type.nix {
|
||||||
inherit lib pkgs;
|
inherit (config.home) homeDirectory;
|
||||||
}).fileType;
|
inherit lib pkgs;
|
||||||
|
}).fileType;
|
||||||
|
|
||||||
defaultCacheHome = "${config.home.homeDirectory}/.cache";
|
defaultCacheHome = "${config.home.homeDirectory}/.cache";
|
||||||
defaultConfigHome = "${config.home.homeDirectory}/.config";
|
defaultConfigHome = "${config.home.homeDirectory}/.config";
|
||||||
defaultDataHome = "${config.home.homeDirectory}/.local/share";
|
defaultDataHome = "${config.home.homeDirectory}/.local/share";
|
||||||
defaultStateHome = "${config.home.homeDirectory}/.local/state";
|
defaultStateHome = "${config.home.homeDirectory}/.local/state";
|
||||||
|
|
||||||
getEnvFallback = name: fallback:
|
getEnvFallback =
|
||||||
let value = builtins.getEnv name;
|
name: fallback:
|
||||||
in if value != "" then value else fallback;
|
let
|
||||||
|
value = builtins.getEnv name;
|
||||||
|
in
|
||||||
|
if value != "" then value else fallback;
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options.xdg = {
|
options.xdg = {
|
||||||
enable = lib.mkEnableOption "management of XDG base directories";
|
enable = lib.mkEnableOption "management of XDG base directories";
|
||||||
|
|
||||||
|
|
@ -64,8 +79,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
dataFile = mkOption {
|
dataFile = mkOption {
|
||||||
type =
|
type = fileType "xdg.dataFile" "<varname>xdg.dataHome</varname>" cfg.dataHome;
|
||||||
fileType "xdg.dataFile" "<varname>xdg.dataHome</varname>" cfg.dataHome;
|
|
||||||
default = { };
|
default = { };
|
||||||
description = ''
|
description = ''
|
||||||
Attribute set of files to link into the user's XDG
|
Attribute set of files to link into the user's XDG
|
||||||
|
|
@ -85,8 +99,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
stateFile = mkOption {
|
stateFile = mkOption {
|
||||||
type = fileType "xdg.stateFile" "<varname>xdg.stateHome</varname>"
|
type = fileType "xdg.stateFile" "<varname>xdg.stateHome</varname>" cfg.stateHome;
|
||||||
cfg.stateHome;
|
|
||||||
default = { };
|
default = { };
|
||||||
description = ''
|
description = ''
|
||||||
Attribute set of files to link into the user's XDG
|
Attribute set of files to link into the user's XDG
|
||||||
|
|
@ -107,34 +120,32 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
(let
|
(
|
||||||
variables = {
|
let
|
||||||
XDG_CACHE_HOME = cfg.cacheHome;
|
variables = {
|
||||||
XDG_CONFIG_HOME = cfg.configHome;
|
XDG_CACHE_HOME = cfg.cacheHome;
|
||||||
XDG_DATA_HOME = cfg.dataHome;
|
XDG_CONFIG_HOME = cfg.configHome;
|
||||||
XDG_STATE_HOME = cfg.stateHome;
|
XDG_DATA_HOME = cfg.dataHome;
|
||||||
};
|
XDG_STATE_HOME = cfg.stateHome;
|
||||||
in mkIf cfg.enable {
|
};
|
||||||
xdg.cacheHome = mkOptionDefault defaultCacheHome;
|
in
|
||||||
xdg.configHome = mkOptionDefault defaultConfigHome;
|
mkIf cfg.enable {
|
||||||
xdg.dataHome = mkOptionDefault defaultDataHome;
|
xdg.cacheHome = mkOptionDefault defaultCacheHome;
|
||||||
xdg.stateHome = mkOptionDefault defaultStateHome;
|
xdg.configHome = mkOptionDefault defaultConfigHome;
|
||||||
|
xdg.dataHome = mkOptionDefault defaultDataHome;
|
||||||
|
xdg.stateHome = mkOptionDefault defaultStateHome;
|
||||||
|
|
||||||
home.sessionVariables = variables;
|
home.sessionVariables = variables;
|
||||||
systemd.user.sessionVariables =
|
systemd.user.sessionVariables = mkIf pkgs.stdenv.hostPlatform.isLinux variables;
|
||||||
mkIf pkgs.stdenv.hostPlatform.isLinux variables;
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
# Legacy non-deterministic setup.
|
# Legacy non-deterministic setup.
|
||||||
(mkIf (!cfg.enable && lib.versionOlder config.home.stateVersion "20.09") {
|
(mkIf (!cfg.enable && lib.versionOlder config.home.stateVersion "20.09") {
|
||||||
xdg.cacheHome =
|
xdg.cacheHome = mkOptionDefault (getEnvFallback "XDG_CACHE_HOME" defaultCacheHome);
|
||||||
mkOptionDefault (getEnvFallback "XDG_CACHE_HOME" defaultCacheHome);
|
xdg.configHome = mkOptionDefault (getEnvFallback "XDG_CONFIG_HOME" defaultConfigHome);
|
||||||
xdg.configHome =
|
xdg.dataHome = mkOptionDefault (getEnvFallback "XDG_DATA_HOME" defaultDataHome);
|
||||||
mkOptionDefault (getEnvFallback "XDG_CONFIG_HOME" defaultConfigHome);
|
xdg.stateHome = mkOptionDefault (getEnvFallback "XDG_STATE_HOME" defaultStateHome);
|
||||||
xdg.dataHome =
|
|
||||||
mkOptionDefault (getEnvFallback "XDG_DATA_HOME" defaultDataHome);
|
|
||||||
xdg.stateHome =
|
|
||||||
mkOptionDefault (getEnvFallback "XDG_STATE_HOME" defaultStateHome);
|
|
||||||
})
|
})
|
||||||
|
|
||||||
# "Modern" deterministic setup.
|
# "Modern" deterministic setup.
|
||||||
|
|
@ -147,18 +158,10 @@ in {
|
||||||
|
|
||||||
{
|
{
|
||||||
home.file = lib.mkMerge [
|
home.file = lib.mkMerge [
|
||||||
(lib.mapAttrs'
|
(lib.mapAttrs' (name: file: lib.nameValuePair "${cfg.cacheHome}/${name}" file) cfg.cacheFile)
|
||||||
(name: file: lib.nameValuePair "${cfg.cacheHome}/${name}" file)
|
(lib.mapAttrs' (name: file: lib.nameValuePair "${cfg.configHome}/${name}" file) cfg.configFile)
|
||||||
cfg.cacheFile)
|
(lib.mapAttrs' (name: file: lib.nameValuePair "${cfg.dataHome}/${name}" file) cfg.dataFile)
|
||||||
(lib.mapAttrs'
|
(lib.mapAttrs' (name: file: lib.nameValuePair "${cfg.stateHome}/${name}" file) cfg.stateFile)
|
||||||
(name: file: lib.nameValuePair "${cfg.configHome}/${name}" file)
|
|
||||||
cfg.configFile)
|
|
||||||
(lib.mapAttrs'
|
|
||||||
(name: file: lib.nameValuePair "${cfg.dataHome}/${name}" file)
|
|
||||||
cfg.dataFile)
|
|
||||||
(lib.mapAttrs'
|
|
||||||
(name: file: lib.nameValuePair "${cfg.stateHome}/${name}" file)
|
|
||||||
cfg.stateFile)
|
|
||||||
{ "${cfg.cacheHome}/.keep".text = ""; }
|
{ "${cfg.cacheHome}/.keep".text = ""; }
|
||||||
{ "${cfg.stateHome}/.keep".text = ""; }
|
{ "${cfg.stateHome}/.keep".text = ""; }
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types;
|
||||||
|
|
@ -8,7 +13,11 @@ let
|
||||||
xfIntVariant = types.submodule {
|
xfIntVariant = types.submodule {
|
||||||
options = {
|
options = {
|
||||||
type = mkOption {
|
type = mkOption {
|
||||||
type = types.enum [ "int" "uint" "uint64" ];
|
type = types.enum [
|
||||||
|
"int"
|
||||||
|
"uint"
|
||||||
|
"uint64"
|
||||||
|
];
|
||||||
description = ''
|
description = ''
|
||||||
To distinguish between int, uint and uint64 in xfconf,
|
To distinguish between int, uint and uint64 in xfconf,
|
||||||
you can specify the type in xfconf with this submodule.
|
you can specify the type in xfconf with this submodule.
|
||||||
|
|
@ -23,38 +32,50 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
withType = v:
|
withType =
|
||||||
if builtins.isAttrs v then [
|
v:
|
||||||
"-t"
|
if builtins.isAttrs v then
|
||||||
v.type
|
[
|
||||||
"-s"
|
"-t"
|
||||||
(toString v.value)
|
v.type
|
||||||
] else if builtins.isBool v then [
|
"-s"
|
||||||
"-t"
|
(toString v.value)
|
||||||
"bool"
|
]
|
||||||
"-s"
|
else if builtins.isBool v then
|
||||||
(if v then "true" else "false")
|
[
|
||||||
] else if builtins.isInt v then [
|
"-t"
|
||||||
"-t"
|
"bool"
|
||||||
"int"
|
"-s"
|
||||||
"-s"
|
(if v then "true" else "false")
|
||||||
(toString v)
|
]
|
||||||
] else if builtins.isFloat v then [
|
else if builtins.isInt v then
|
||||||
"-t"
|
[
|
||||||
"double"
|
"-t"
|
||||||
"-s"
|
"int"
|
||||||
(toString v)
|
"-s"
|
||||||
] else if builtins.isString v then [
|
(toString v)
|
||||||
"-t"
|
]
|
||||||
"string"
|
else if builtins.isFloat v then
|
||||||
"-s"
|
[
|
||||||
v
|
"-t"
|
||||||
] else if builtins.isList v then
|
"double"
|
||||||
|
"-s"
|
||||||
|
(toString v)
|
||||||
|
]
|
||||||
|
else if builtins.isString v then
|
||||||
|
[
|
||||||
|
"-t"
|
||||||
|
"string"
|
||||||
|
"-s"
|
||||||
|
v
|
||||||
|
]
|
||||||
|
else if builtins.isList v then
|
||||||
[ "-a" ] ++ lib.concatMap withType v
|
[ "-a" ] ++ lib.concatMap withType v
|
||||||
else
|
else
|
||||||
throw "unexpected xfconf type: ${builtins.typeOf v}";
|
throw "unexpected xfconf type: ${builtins.typeOf v}";
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.chuangzhu ];
|
meta.maintainers = [ lib.maintainers.chuangzhu ];
|
||||||
|
|
||||||
options.xfconf = {
|
options.xfconf = {
|
||||||
|
|
@ -73,10 +94,20 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
settings = mkOption {
|
settings = mkOption {
|
||||||
type = with types;
|
type =
|
||||||
# xfIntVariant must come AFTER str; otherwise strings are treated as submodule imports...
|
with types;
|
||||||
let value = nullOr (oneOf [ bool int float str xfIntVariant ]);
|
# xfIntVariant must come AFTER str; otherwise strings are treated as submodule imports...
|
||||||
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";
|
description = "xfconf settings";
|
||||||
};
|
};
|
||||||
default = { };
|
default = { };
|
||||||
|
|
@ -99,30 +130,33 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf (cfg.enable && cfg.settings != { }) {
|
config = lib.mkIf (cfg.enable && cfg.settings != { }) {
|
||||||
assertions =
|
assertions = [ (lib.hm.assertions.assertPlatform "xfconf" pkgs lib.platforms.linux) ];
|
||||||
[ (lib.hm.assertions.assertPlatform "xfconf" pkgs lib.platforms.linux) ];
|
|
||||||
|
|
||||||
home.activation.xfconfSettings = lib.hm.dag.entryAfter [ "installPackages" ]
|
home.activation.xfconfSettings = lib.hm.dag.entryAfter [ "installPackages" ] (
|
||||||
(let
|
let
|
||||||
mkCommand = channel: property: value: ''
|
mkCommand = channel: property: value: ''
|
||||||
run ${pkgs.xfce.xfconf}/bin/xfconf-query \
|
run ${pkgs.xfce.xfconf}/bin/xfconf-query \
|
||||||
${
|
${lib.escapeShellArgs (
|
||||||
lib.escapeShellArgs ([ "-c" channel "-p" "/${property}" ]
|
[
|
||||||
++ (if value == null then
|
"-c"
|
||||||
[ "-r" ]
|
channel
|
||||||
else
|
"-p"
|
||||||
[ "-n" ] ++ withType value))
|
"/${property}"
|
||||||
}
|
]
|
||||||
|
++ (if value == null then [ "-r" ] else [ "-n" ] ++ withType value)
|
||||||
|
)}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
commands = lib.mapAttrsToList (channel: properties:
|
commands = lib.mapAttrsToList (
|
||||||
lib.mapAttrsToList (mkCommand channel) properties) cfg.settings;
|
channel: properties: lib.mapAttrsToList (mkCommand channel) properties
|
||||||
|
) cfg.settings;
|
||||||
|
|
||||||
load = pkgs.writeShellScript "load-xfconf" ''
|
load = pkgs.writeShellScript "load-xfconf" ''
|
||||||
${config.lib.bash.initHomeManagerLib}
|
${config.lib.bash.initHomeManagerLib}
|
||||||
${lib.concatMapStrings lib.concatStrings commands}
|
${lib.concatMapStrings lib.concatStrings commands}
|
||||||
'';
|
'';
|
||||||
in ''
|
in
|
||||||
|
''
|
||||||
if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then
|
if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then
|
||||||
export DBUS_RUN_SESSION_CMD=""
|
export DBUS_RUN_SESSION_CMD=""
|
||||||
else
|
else
|
||||||
|
|
@ -132,6 +166,7 @@ in {
|
||||||
run $DBUS_RUN_SESSION_CMD ${load}
|
run $DBUS_RUN_SESSION_CMD ${load}
|
||||||
|
|
||||||
unset DBUS_RUN_SESSION_CMD
|
unset DBUS_RUN_SESSION_CMD
|
||||||
'');
|
''
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,492 +1,499 @@
|
||||||
{ pkgs
|
{
|
||||||
|
pkgs,
|
||||||
|
|
||||||
# Note, this should be "the standard library" + HM extensions.
|
# Note, this should be "the standard library" + HM extensions.
|
||||||
, lib
|
lib,
|
||||||
|
|
||||||
# Whether to enable module type checking.
|
# Whether to enable module type checking.
|
||||||
, check ? true
|
check ? true,
|
||||||
|
|
||||||
# If disabled, the pkgs attribute passed to this function is used instead.
|
# If disabled, the pkgs attribute passed to this function is used instead.
|
||||||
, useNixpkgsModule ? true }:
|
useNixpkgsModule ? true,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
modules = [
|
modules =
|
||||||
./accounts/email.nix
|
[
|
||||||
./accounts/calendar.nix
|
./accounts/email.nix
|
||||||
./accounts/contacts.nix
|
./accounts/calendar.nix
|
||||||
./config/home-cursor.nix
|
./accounts/contacts.nix
|
||||||
./config/i18n.nix
|
./config/home-cursor.nix
|
||||||
./files.nix
|
./config/i18n.nix
|
||||||
./home-environment.nix
|
./files.nix
|
||||||
./i18n/input-method/default.nix
|
./home-environment.nix
|
||||||
./launchd/default.nix
|
./i18n/input-method/default.nix
|
||||||
./manual.nix
|
./launchd/default.nix
|
||||||
./misc/dconf.nix
|
./manual.nix
|
||||||
./misc/debug.nix
|
./misc/dconf.nix
|
||||||
./misc/editorconfig.nix
|
./misc/debug.nix
|
||||||
./misc/fontconfig.nix
|
./misc/editorconfig.nix
|
||||||
./misc/gtk.nix
|
./misc/fontconfig.nix
|
||||||
./misc/lib.nix
|
./misc/gtk.nix
|
||||||
./misc/mozilla-messaging-hosts.nix
|
./misc/lib.nix
|
||||||
./misc/news.nix
|
./misc/mozilla-messaging-hosts.nix
|
||||||
./misc/nixgl.nix
|
./misc/news.nix
|
||||||
./misc/numlock.nix
|
./misc/nixgl.nix
|
||||||
./misc/pam.nix
|
./misc/numlock.nix
|
||||||
./misc/qt.nix
|
./misc/pam.nix
|
||||||
./misc/qt/kconfig.nix
|
./misc/qt.nix
|
||||||
./misc/shell.nix
|
./misc/qt/kconfig.nix
|
||||||
./misc/specialisation.nix
|
./misc/shell.nix
|
||||||
./misc/submodule-support.nix
|
./misc/specialisation.nix
|
||||||
./misc/tmpfiles.nix
|
./misc/submodule-support.nix
|
||||||
./misc/uninstall.nix
|
./misc/tmpfiles.nix
|
||||||
./misc/version.nix
|
./misc/uninstall.nix
|
||||||
./misc/vte.nix
|
./misc/version.nix
|
||||||
./misc/xdg-autostart.nix
|
./misc/vte.nix
|
||||||
./misc/xdg-desktop-entries.nix
|
./misc/xdg-autostart.nix
|
||||||
./misc/xdg-mime-apps.nix
|
./misc/xdg-desktop-entries.nix
|
||||||
./misc/xdg-mime.nix
|
./misc/xdg-mime-apps.nix
|
||||||
./misc/xdg-portal.nix
|
./misc/xdg-mime.nix
|
||||||
./misc/xdg-system-dirs.nix
|
./misc/xdg-portal.nix
|
||||||
./misc/xdg-user-dirs.nix
|
./misc/xdg-system-dirs.nix
|
||||||
./misc/xdg.nix
|
./misc/xdg-user-dirs.nix
|
||||||
./misc/xfconf.nix
|
./misc/xdg.nix
|
||||||
./programs/abook.nix
|
./misc/xfconf.nix
|
||||||
./programs/aerc.nix
|
./programs/abook.nix
|
||||||
./programs/aerospace.nix
|
./programs/aerc.nix
|
||||||
./programs/afew.nix
|
./programs/aerospace.nix
|
||||||
./programs/alacritty.nix
|
./programs/afew.nix
|
||||||
./programs/alot.nix
|
./programs/alacritty.nix
|
||||||
./programs/antidote.nix
|
./programs/alot.nix
|
||||||
./programs/aria2.nix
|
./programs/antidote.nix
|
||||||
./programs/astroid.nix
|
./programs/aria2.nix
|
||||||
./programs/atuin.nix
|
./programs/astroid.nix
|
||||||
./programs/autojump.nix
|
./programs/atuin.nix
|
||||||
./programs/autorandr.nix
|
./programs/autojump.nix
|
||||||
./programs/awscli.nix
|
./programs/autorandr.nix
|
||||||
./programs/bash.nix
|
./programs/awscli.nix
|
||||||
./programs/bashmount.nix
|
./programs/bash.nix
|
||||||
./programs/bat.nix
|
./programs/bashmount.nix
|
||||||
./programs/bacon.nix
|
./programs/bat.nix
|
||||||
./programs/beets.nix
|
./programs/bacon.nix
|
||||||
./programs/bemenu.nix
|
./programs/beets.nix
|
||||||
./programs/borgmatic.nix
|
./programs/bemenu.nix
|
||||||
./programs/bottom.nix
|
./programs/borgmatic.nix
|
||||||
./programs/boxxy.nix
|
./programs/bottom.nix
|
||||||
./programs/broot.nix
|
./programs/boxxy.nix
|
||||||
./programs/browserpass.nix
|
./programs/broot.nix
|
||||||
./programs/btop.nix
|
./programs/browserpass.nix
|
||||||
./programs/bun.nix
|
./programs/btop.nix
|
||||||
./programs/carapace.nix
|
./programs/bun.nix
|
||||||
./programs/cava.nix
|
./programs/carapace.nix
|
||||||
./programs/cavalier.nix
|
./programs/cava.nix
|
||||||
./programs/chromium.nix
|
./programs/cavalier.nix
|
||||||
./programs/cmus.nix
|
./programs/chromium.nix
|
||||||
./programs/command-not-found/command-not-found.nix
|
./programs/cmus.nix
|
||||||
./programs/comodoro.nix
|
./programs/command-not-found/command-not-found.nix
|
||||||
./programs/darcs.nix
|
./programs/comodoro.nix
|
||||||
./programs/dircolors.nix
|
./programs/darcs.nix
|
||||||
./programs/direnv.nix
|
./programs/dircolors.nix
|
||||||
./programs/discocss.nix
|
./programs/direnv.nix
|
||||||
./programs/distrobox.nix
|
./programs/discocss.nix
|
||||||
./programs/earthly.nix
|
./programs/distrobox.nix
|
||||||
./programs/eclipse.nix
|
./programs/earthly.nix
|
||||||
./programs/emacs.nix
|
./programs/eclipse.nix
|
||||||
./programs/eww.nix
|
./programs/emacs.nix
|
||||||
./programs/eza.nix
|
./programs/eww.nix
|
||||||
./programs/fastfetch.nix
|
./programs/eza.nix
|
||||||
./programs/fd.nix
|
./programs/fastfetch.nix
|
||||||
./programs/feh.nix
|
./programs/fd.nix
|
||||||
./programs/firefox.nix
|
./programs/feh.nix
|
||||||
./programs/fish.nix
|
./programs/firefox.nix
|
||||||
./programs/floorp.nix
|
./programs/fish.nix
|
||||||
./programs/foot.nix
|
./programs/floorp.nix
|
||||||
./programs/freetube.nix
|
./programs/foot.nix
|
||||||
./programs/fuzzel.nix
|
./programs/freetube.nix
|
||||||
./programs/fzf.nix
|
./programs/fuzzel.nix
|
||||||
./programs/gallery-dl.nix
|
./programs/fzf.nix
|
||||||
./programs/getmail.nix
|
./programs/gallery-dl.nix
|
||||||
./programs/gh.nix
|
./programs/getmail.nix
|
||||||
./programs/gh-dash.nix
|
./programs/gh.nix
|
||||||
./programs/ghostty.nix
|
./programs/gh-dash.nix
|
||||||
./programs/git-cliff.nix
|
./programs/ghostty.nix
|
||||||
./programs/git-credential-oauth.nix
|
./programs/git-cliff.nix
|
||||||
./programs/git-worktree-switcher.nix
|
./programs/git-credential-oauth.nix
|
||||||
./programs/git.nix
|
./programs/git-worktree-switcher.nix
|
||||||
./programs/gitui.nix
|
./programs/git.nix
|
||||||
./programs/gnome-shell.nix
|
./programs/gitui.nix
|
||||||
./programs/gnome-terminal.nix
|
./programs/gnome-shell.nix
|
||||||
./programs/go.nix
|
./programs/gnome-terminal.nix
|
||||||
./programs/gpg.nix
|
./programs/go.nix
|
||||||
./programs/gradle.nix
|
./programs/gpg.nix
|
||||||
./programs/granted.nix
|
./programs/gradle.nix
|
||||||
./programs/havoc.nix
|
./programs/granted.nix
|
||||||
./programs/helix.nix
|
./programs/havoc.nix
|
||||||
./programs/hexchat.nix
|
./programs/helix.nix
|
||||||
./programs/himalaya.nix
|
./programs/hexchat.nix
|
||||||
./programs/home-manager.nix
|
./programs/himalaya.nix
|
||||||
./programs/hstr.nix
|
./programs/home-manager.nix
|
||||||
./programs/htop.nix
|
./programs/hstr.nix
|
||||||
./programs/hyfetch.nix
|
./programs/htop.nix
|
||||||
./programs/hyprlock.nix
|
./programs/hyfetch.nix
|
||||||
./programs/i3blocks.nix
|
./programs/hyprlock.nix
|
||||||
./programs/i3status-rust.nix
|
./programs/i3blocks.nix
|
||||||
./programs/i3status.nix
|
./programs/i3status-rust.nix
|
||||||
./programs/iamb.nix
|
./programs/i3status.nix
|
||||||
./programs/imv.nix
|
./programs/iamb.nix
|
||||||
./programs/info.nix
|
./programs/imv.nix
|
||||||
./programs/ion.nix
|
./programs/info.nix
|
||||||
./programs/irssi.nix
|
./programs/ion.nix
|
||||||
./programs/java.nix
|
./programs/irssi.nix
|
||||||
./programs/jetbrains-remote.nix
|
./programs/java.nix
|
||||||
./programs/jq.nix
|
./programs/jetbrains-remote.nix
|
||||||
./programs/jqp.nix
|
./programs/jq.nix
|
||||||
./programs/jujutsu.nix
|
./programs/jqp.nix
|
||||||
./programs/joshuto.nix
|
./programs/jujutsu.nix
|
||||||
./programs/joplin-desktop.nix
|
./programs/joshuto.nix
|
||||||
./programs/just.nix
|
./programs/joplin-desktop.nix
|
||||||
./programs/k9s.nix
|
./programs/just.nix
|
||||||
./programs/kakoune.nix
|
./programs/k9s.nix
|
||||||
./programs/keychain.nix
|
./programs/kakoune.nix
|
||||||
./programs/khal.nix
|
./programs/keychain.nix
|
||||||
./programs/khard.nix
|
./programs/khal.nix
|
||||||
./programs/kitty.nix
|
./programs/khard.nix
|
||||||
./programs/kodi.nix
|
./programs/kitty.nix
|
||||||
./programs/kubecolor.nix
|
./programs/kodi.nix
|
||||||
./programs/lapce.nix
|
./programs/kubecolor.nix
|
||||||
./programs/lazydocker.nix
|
./programs/lapce.nix
|
||||||
./programs/lazygit.nix
|
./programs/lazydocker.nix
|
||||||
./programs/ledger.nix
|
./programs/lazygit.nix
|
||||||
./programs/less.nix
|
./programs/ledger.nix
|
||||||
./programs/lesspipe.nix
|
./programs/less.nix
|
||||||
./programs/lf.nix
|
./programs/lesspipe.nix
|
||||||
./programs/librewolf.nix
|
./programs/lf.nix
|
||||||
./programs/lieer.nix
|
./programs/librewolf.nix
|
||||||
./programs/looking-glass-client.nix
|
./programs/lieer.nix
|
||||||
./programs/lsd.nix
|
./programs/looking-glass-client.nix
|
||||||
./programs/man.nix
|
./programs/lsd.nix
|
||||||
./programs/mangohud.nix
|
./programs/man.nix
|
||||||
./programs/matplotlib.nix
|
./programs/mangohud.nix
|
||||||
./programs/mbsync.nix
|
./programs/matplotlib.nix
|
||||||
./programs/mcfly.nix
|
./programs/mbsync.nix
|
||||||
./programs/mercurial.nix
|
./programs/mcfly.nix
|
||||||
./programs/mergiraf.nix
|
./programs/mercurial.nix
|
||||||
./programs/micro.nix
|
./programs/mergiraf.nix
|
||||||
./programs/mise.nix
|
./programs/micro.nix
|
||||||
./programs/mods.nix
|
./programs/mise.nix
|
||||||
./programs/mpv.nix
|
./programs/mods.nix
|
||||||
./programs/mr.nix
|
./programs/mpv.nix
|
||||||
./programs/msmtp.nix
|
./programs/mr.nix
|
||||||
./programs/mu.nix
|
./programs/msmtp.nix
|
||||||
./programs/mujmap.nix
|
./programs/mu.nix
|
||||||
./programs/navi.nix
|
./programs/mujmap.nix
|
||||||
./programs/ncmpcpp.nix
|
./programs/navi.nix
|
||||||
./programs/ncspot.nix
|
./programs/ncmpcpp.nix
|
||||||
./programs/ne.nix
|
./programs/ncspot.nix
|
||||||
./programs/neomutt.nix
|
./programs/ne.nix
|
||||||
./programs/neovide.nix
|
./programs/neomutt.nix
|
||||||
./programs/neovim.nix
|
./programs/neovide.nix
|
||||||
./programs/newsboat.nix
|
./programs/neovim.nix
|
||||||
./programs/nh.nix
|
./programs/newsboat.nix
|
||||||
./programs/nheko.nix
|
./programs/nh.nix
|
||||||
./programs/nix-index.nix
|
./programs/nheko.nix
|
||||||
./programs/nix-your-shell.nix
|
./programs/nix-index.nix
|
||||||
./programs/nnn.nix
|
./programs/nix-your-shell.nix
|
||||||
./programs/noti.nix
|
./programs/nnn.nix
|
||||||
./programs/notmuch.nix
|
./programs/noti.nix
|
||||||
./programs/nushell.nix
|
./programs/notmuch.nix
|
||||||
./programs/obs-studio.nix
|
./programs/nushell.nix
|
||||||
./programs/octant.nix
|
./programs/obs-studio.nix
|
||||||
./programs/offlineimap.nix
|
./programs/octant.nix
|
||||||
./programs/oh-my-posh.nix
|
./programs/offlineimap.nix
|
||||||
./programs/onlyoffice.nix
|
./programs/oh-my-posh.nix
|
||||||
./programs/opam.nix
|
./programs/onlyoffice.nix
|
||||||
./programs/openstackclient.nix
|
./programs/opam.nix
|
||||||
./programs/pandoc.nix
|
./programs/openstackclient.nix
|
||||||
./programs/papis.nix
|
./programs/pandoc.nix
|
||||||
./programs/password-store.nix
|
./programs/papis.nix
|
||||||
./programs/pay-respects.nix
|
./programs/password-store.nix
|
||||||
./programs/pazi.nix
|
./programs/pay-respects.nix
|
||||||
./programs/pet.nix
|
./programs/pazi.nix
|
||||||
./programs/pidgin.nix
|
./programs/pet.nix
|
||||||
./programs/pistol.nix
|
./programs/pidgin.nix
|
||||||
./programs/piston-cli.nix
|
./programs/pistol.nix
|
||||||
./programs/pls.nix
|
./programs/piston-cli.nix
|
||||||
./programs/poetry.nix
|
./programs/pls.nix
|
||||||
./programs/powerline-go.nix
|
./programs/poetry.nix
|
||||||
./programs/pqiv.nix
|
./programs/powerline-go.nix
|
||||||
./programs/pubs.nix
|
./programs/pqiv.nix
|
||||||
./programs/pyenv.nix
|
./programs/pubs.nix
|
||||||
./programs/pylint.nix
|
./programs/pyenv.nix
|
||||||
./programs/qcal.nix
|
./programs/pylint.nix
|
||||||
./programs/qutebrowser.nix
|
./programs/qcal.nix
|
||||||
./programs/ranger.nix
|
./programs/qutebrowser.nix
|
||||||
./programs/rbw.nix
|
./programs/ranger.nix
|
||||||
./programs/rclone.nix
|
./programs/rbw.nix
|
||||||
./programs/readline.nix
|
./programs/rclone.nix
|
||||||
./programs/rio.nix
|
./programs/readline.nix
|
||||||
./programs/ripgrep.nix
|
./programs/rio.nix
|
||||||
./programs/ripgrep-all.nix
|
./programs/ripgrep.nix
|
||||||
./programs/rofi-pass.nix
|
./programs/ripgrep-all.nix
|
||||||
./programs/rofi.nix
|
./programs/rofi-pass.nix
|
||||||
./programs/rtorrent.nix
|
./programs/rofi.nix
|
||||||
./programs/ruff.nix
|
./programs/rtorrent.nix
|
||||||
./programs/sagemath.nix
|
./programs/ruff.nix
|
||||||
./programs/sapling.nix
|
./programs/sagemath.nix
|
||||||
./programs/sbt.nix
|
./programs/sapling.nix
|
||||||
./programs/scmpuff.nix
|
./programs/sbt.nix
|
||||||
./programs/script-directory.nix
|
./programs/scmpuff.nix
|
||||||
./programs/senpai.nix
|
./programs/script-directory.nix
|
||||||
./programs/sesh.nix
|
./programs/senpai.nix
|
||||||
./programs/sftpman.nix
|
./programs/sesh.nix
|
||||||
./programs/sioyek.nix
|
./programs/sftpman.nix
|
||||||
./programs/skim.nix
|
./programs/sioyek.nix
|
||||||
./programs/sm64ex.nix
|
./programs/skim.nix
|
||||||
./programs/smug.nix
|
./programs/sm64ex.nix
|
||||||
./programs/spotify-player.nix
|
./programs/smug.nix
|
||||||
./programs/sqls.nix
|
./programs/spotify-player.nix
|
||||||
./programs/ssh.nix
|
./programs/sqls.nix
|
||||||
./programs/starship.nix
|
./programs/ssh.nix
|
||||||
./programs/streamlink.nix
|
./programs/starship.nix
|
||||||
./programs/swayimg.nix
|
./programs/streamlink.nix
|
||||||
./programs/swaylock.nix
|
./programs/swayimg.nix
|
||||||
./programs/swayr.nix
|
./programs/swaylock.nix
|
||||||
./programs/taskwarrior.nix
|
./programs/swayr.nix
|
||||||
./programs/tealdeer.nix
|
./programs/taskwarrior.nix
|
||||||
./programs/terminator.nix
|
./programs/tealdeer.nix
|
||||||
./programs/termite.nix
|
./programs/terminator.nix
|
||||||
./programs/tex-fmt.nix
|
./programs/termite.nix
|
||||||
./programs/texlive.nix
|
./programs/tex-fmt.nix
|
||||||
./programs/thefuck.nix
|
./programs/texlive.nix
|
||||||
./programs/thunderbird.nix
|
./programs/thefuck.nix
|
||||||
./programs/timidity.nix
|
./programs/thunderbird.nix
|
||||||
./programs/tint2.nix
|
./programs/timidity.nix
|
||||||
./programs/tiny.nix
|
./programs/tint2.nix
|
||||||
./programs/tmate.nix
|
./programs/tiny.nix
|
||||||
./programs/tmux.nix
|
./programs/tmate.nix
|
||||||
./programs/tofi.nix
|
./programs/tmux.nix
|
||||||
./programs/todoman.nix
|
./programs/tofi.nix
|
||||||
./programs/topgrade.nix
|
./programs/todoman.nix
|
||||||
./programs/translate-shell.nix
|
./programs/topgrade.nix
|
||||||
./programs/urxvt.nix
|
./programs/translate-shell.nix
|
||||||
./programs/vdirsyncer.nix
|
./programs/urxvt.nix
|
||||||
./programs/vifm.nix
|
./programs/vdirsyncer.nix
|
||||||
./programs/vim-vint.nix
|
./programs/vifm.nix
|
||||||
./programs/vim.nix
|
./programs/vim-vint.nix
|
||||||
./programs/vinegar.nix
|
./programs/vim.nix
|
||||||
./programs/vscode.nix
|
./programs/vinegar.nix
|
||||||
./programs/vscode/haskell.nix
|
./programs/vscode.nix
|
||||||
./programs/pywal.nix
|
./programs/vscode/haskell.nix
|
||||||
./programs/rbenv.nix
|
./programs/pywal.nix
|
||||||
./programs/watson.nix
|
./programs/rbenv.nix
|
||||||
./programs/waylogout.nix
|
./programs/watson.nix
|
||||||
./programs/waybar.nix
|
./programs/waylogout.nix
|
||||||
./programs/wezterm.nix
|
./programs/waybar.nix
|
||||||
./programs/wlogout.nix
|
./programs/wezterm.nix
|
||||||
./programs/wofi.nix
|
./programs/wlogout.nix
|
||||||
./programs/xmobar.nix
|
./programs/wofi.nix
|
||||||
./programs/xplr.nix
|
./programs/xmobar.nix
|
||||||
./programs/yambar.nix
|
./programs/xplr.nix
|
||||||
./programs/yazi.nix
|
./programs/yambar.nix
|
||||||
./programs/yt-dlp.nix
|
./programs/yazi.nix
|
||||||
./programs/z-lua.nix
|
./programs/yt-dlp.nix
|
||||||
./programs/zathura.nix
|
./programs/z-lua.nix
|
||||||
./programs/zed-editor.nix
|
./programs/zathura.nix
|
||||||
./programs/zellij.nix
|
./programs/zed-editor.nix
|
||||||
./programs/zk.nix
|
./programs/zellij.nix
|
||||||
./programs/zoxide.nix
|
./programs/zk.nix
|
||||||
./programs/zplug.nix
|
./programs/zoxide.nix
|
||||||
./programs/zsh.nix
|
./programs/zplug.nix
|
||||||
./programs/zsh/prezto.nix
|
./programs/zsh.nix
|
||||||
./programs/zsh/zsh-abbr.nix
|
./programs/zsh/prezto.nix
|
||||||
./services/activitywatch.nix
|
./programs/zsh/zsh-abbr.nix
|
||||||
./services/amberol.nix
|
./services/activitywatch.nix
|
||||||
./services/arrpc.nix
|
./services/amberol.nix
|
||||||
./services/autorandr.nix
|
./services/arrpc.nix
|
||||||
./services/avizo.nix
|
./services/autorandr.nix
|
||||||
./services/barrier.nix
|
./services/avizo.nix
|
||||||
./services/batsignal.nix
|
./services/barrier.nix
|
||||||
./services/betterlockscreen.nix
|
./services/batsignal.nix
|
||||||
./services/blanket.nix
|
./services/betterlockscreen.nix
|
||||||
./services/blueman-applet.nix
|
./services/blanket.nix
|
||||||
./services/borgmatic.nix
|
./services/blueman-applet.nix
|
||||||
./services/cachix-agent.nix
|
./services/borgmatic.nix
|
||||||
./services/caffeine.nix
|
./services/cachix-agent.nix
|
||||||
./services/cbatticon.nix
|
./services/caffeine.nix
|
||||||
./services/cliphist.nix
|
./services/cbatticon.nix
|
||||||
./services/clipman.nix
|
./services/cliphist.nix
|
||||||
./services/clipmenu.nix
|
./services/clipman.nix
|
||||||
./services/clipse.nix
|
./services/clipmenu.nix
|
||||||
./services/comodoro.nix
|
./services/clipse.nix
|
||||||
./services/conky.nix
|
./services/comodoro.nix
|
||||||
./services/copyq.nix
|
./services/conky.nix
|
||||||
./services/darkman.nix
|
./services/copyq.nix
|
||||||
./services/davmail.nix
|
./services/darkman.nix
|
||||||
./services/devilspie2.nix
|
./services/davmail.nix
|
||||||
./services/dropbox.nix
|
./services/devilspie2.nix
|
||||||
./services/dunst.nix
|
./services/dropbox.nix
|
||||||
./services/dwm-status.nix
|
./services/dunst.nix
|
||||||
./services/easyeffects.nix
|
./services/dwm-status.nix
|
||||||
./services/emacs.nix
|
./services/easyeffects.nix
|
||||||
./services/etesync-dav.nix
|
./services/emacs.nix
|
||||||
./services/espanso.nix
|
./services/etesync-dav.nix
|
||||||
./services/flameshot.nix
|
./services/espanso.nix
|
||||||
./services/fluidsynth.nix
|
./services/flameshot.nix
|
||||||
./services/fnott.nix
|
./services/fluidsynth.nix
|
||||||
./services/fusuma.nix
|
./services/fnott.nix
|
||||||
./services/getmail.nix
|
./services/fusuma.nix
|
||||||
./services/git-sync.nix
|
./services/getmail.nix
|
||||||
./services/glance.nix
|
./services/git-sync.nix
|
||||||
./services/gnome-keyring.nix
|
./services/glance.nix
|
||||||
./services/gpg-agent.nix
|
./services/gnome-keyring.nix
|
||||||
./services/grobi.nix
|
./services/gpg-agent.nix
|
||||||
./services/gromit-mpx.nix
|
./services/grobi.nix
|
||||||
./services/home-manager-auto-expire.nix
|
./services/gromit-mpx.nix
|
||||||
./services/home-manager-auto-upgrade.nix
|
./services/home-manager-auto-expire.nix
|
||||||
./services/hound.nix
|
./services/home-manager-auto-upgrade.nix
|
||||||
./services/hypridle.nix
|
./services/hound.nix
|
||||||
./services/hyprpaper.nix
|
./services/hypridle.nix
|
||||||
./services/hyprpolkitagent.nix
|
./services/hyprpaper.nix
|
||||||
./services/imapnotify.nix
|
./services/hyprpolkitagent.nix
|
||||||
./services/jankyborders.nix
|
./services/imapnotify.nix
|
||||||
./services/kanshi.nix
|
./services/jankyborders.nix
|
||||||
./services/kbfs.nix
|
./services/kanshi.nix
|
||||||
./services/kdeconnect.nix
|
./services/kbfs.nix
|
||||||
./services/keybase.nix
|
./services/kdeconnect.nix
|
||||||
./services/keynav.nix
|
./services/keybase.nix
|
||||||
./services/librespot.nix
|
./services/keynav.nix
|
||||||
./services/lieer.nix
|
./services/librespot.nix
|
||||||
./services/linux-wallpaperengine.nix
|
./services/lieer.nix
|
||||||
./services/listenbrainz-mpd.nix
|
./services/linux-wallpaperengine.nix
|
||||||
./services/lorri.nix
|
./services/listenbrainz-mpd.nix
|
||||||
./services/lxqt-policykit-agent.nix
|
./services/lorri.nix
|
||||||
./services/macos-remap-keys
|
./services/lxqt-policykit-agent.nix
|
||||||
./services/mako.nix
|
./services/macos-remap-keys
|
||||||
./services/mbsync.nix
|
./services/mako.nix
|
||||||
./services/megasync.nix
|
./services/mbsync.nix
|
||||||
./services/mopidy.nix
|
./services/megasync.nix
|
||||||
./services/mpd.nix
|
./services/mopidy.nix
|
||||||
./services/mpdris2.nix
|
./services/mpd.nix
|
||||||
./services/mpdscribble.nix
|
./services/mpdris2.nix
|
||||||
./services/mpd-discord-rpc.nix
|
./services/mpdscribble.nix
|
||||||
./services/mpd-mpris.nix
|
./services/mpd-discord-rpc.nix
|
||||||
./services/mpris-proxy.nix
|
./services/mpd-mpris.nix
|
||||||
./services/muchsync.nix
|
./services/mpris-proxy.nix
|
||||||
./services/network-manager-applet.nix
|
./services/muchsync.nix
|
||||||
./services/nextcloud-client.nix
|
./services/network-manager-applet.nix
|
||||||
./services/nix-gc.nix
|
./services/nextcloud-client.nix
|
||||||
./services/notify-osd.nix
|
./services/nix-gc.nix
|
||||||
./services/ollama.nix
|
./services/notify-osd.nix
|
||||||
./services/opensnitch-ui.nix
|
./services/ollama.nix
|
||||||
./services/osmscout-server.nix
|
./services/opensnitch-ui.nix
|
||||||
./services/owncloud-client.nix
|
./services/osmscout-server.nix
|
||||||
./services/pantalaimon.nix
|
./services/owncloud-client.nix
|
||||||
./services/parcellite.nix
|
./services/pantalaimon.nix
|
||||||
./services/pass-secret-service.nix
|
./services/parcellite.nix
|
||||||
./services/pasystray.nix
|
./services/pass-secret-service.nix
|
||||||
./services/pbgopy.nix
|
./services/pasystray.nix
|
||||||
./services/picom.nix
|
./services/pbgopy.nix
|
||||||
./services/plan9port.nix
|
./services/picom.nix
|
||||||
./services/playerctld.nix
|
./services/plan9port.nix
|
||||||
./services/plex-mpv-shim.nix
|
./services/playerctld.nix
|
||||||
./services/podman-linux
|
./services/plex-mpv-shim.nix
|
||||||
./services/polkit-gnome.nix
|
./services/podman-linux
|
||||||
./services/polybar.nix
|
./services/polkit-gnome.nix
|
||||||
./services/poweralertd.nix
|
./services/polybar.nix
|
||||||
./services/psd.nix
|
./services/poweralertd.nix
|
||||||
./services/pueue.nix
|
./services/psd.nix
|
||||||
./services/pulseeffects.nix
|
./services/pueue.nix
|
||||||
./services/random-background.nix
|
./services/pulseeffects.nix
|
||||||
./services/recoll.nix
|
./services/random-background.nix
|
||||||
./services/redshift-gammastep/gammastep.nix
|
./services/recoll.nix
|
||||||
./services/redshift-gammastep/redshift.nix
|
./services/redshift-gammastep/gammastep.nix
|
||||||
./services/remmina.nix
|
./services/redshift-gammastep/redshift.nix
|
||||||
./services/rsibreak.nix
|
./services/remmina.nix
|
||||||
./services/safeeyes.nix
|
./services/rsibreak.nix
|
||||||
./services/screen-locker.nix
|
./services/safeeyes.nix
|
||||||
./services/sctd.nix
|
./services/screen-locker.nix
|
||||||
./services/signaturepdf.nix
|
./services/sctd.nix
|
||||||
./services/skhd.nix
|
./services/signaturepdf.nix
|
||||||
./services/snixembed.nix
|
./services/skhd.nix
|
||||||
./services/spotifyd.nix
|
./services/snixembed.nix
|
||||||
./services/ssh-agent.nix
|
./services/spotifyd.nix
|
||||||
./services/stalonetray.nix
|
./services/ssh-agent.nix
|
||||||
./services/status-notifier-watcher.nix
|
./services/stalonetray.nix
|
||||||
./services/swayidle.nix
|
./services/status-notifier-watcher.nix
|
||||||
./services/swaync.nix
|
./services/swayidle.nix
|
||||||
./services/swayosd.nix
|
./services/swaync.nix
|
||||||
./services/swww.nix
|
./services/swayosd.nix
|
||||||
./services/sxhkd.nix
|
./services/swww.nix
|
||||||
./services/syncthing.nix
|
./services/sxhkd.nix
|
||||||
./services/systembus-notify.nix
|
./services/syncthing.nix
|
||||||
./services/taffybar.nix
|
./services/systembus-notify.nix
|
||||||
./services/tahoe-lafs.nix
|
./services/taffybar.nix
|
||||||
./services/taskwarrior-sync.nix
|
./services/tahoe-lafs.nix
|
||||||
./services/tldr-update.nix
|
./services/taskwarrior-sync.nix
|
||||||
./services/trayer.nix
|
./services/tldr-update.nix
|
||||||
./services/trayscale.nix
|
./services/trayer.nix
|
||||||
./services/twmn.nix
|
./services/trayscale.nix
|
||||||
./services/udiskie.nix
|
./services/twmn.nix
|
||||||
./services/unclutter.nix
|
./services/udiskie.nix
|
||||||
./services/unison.nix
|
./services/unclutter.nix
|
||||||
./services/vdirsyncer.nix
|
./services/unison.nix
|
||||||
./services/volnoti.nix
|
./services/vdirsyncer.nix
|
||||||
./services/window-managers/awesome.nix
|
./services/volnoti.nix
|
||||||
./services/window-managers/bspwm/default.nix
|
./services/window-managers/awesome.nix
|
||||||
./services/window-managers/fluxbox.nix
|
./services/window-managers/bspwm/default.nix
|
||||||
./services/window-managers/herbstluftwm.nix
|
./services/window-managers/fluxbox.nix
|
||||||
./services/window-managers/hyprland.nix
|
./services/window-managers/herbstluftwm.nix
|
||||||
./services/window-managers/i3-sway/i3.nix
|
./services/window-managers/hyprland.nix
|
||||||
./services/window-managers/i3-sway/sway.nix
|
./services/window-managers/i3-sway/i3.nix
|
||||||
./services/window-managers/i3-sway/swaynag.nix
|
./services/window-managers/i3-sway/sway.nix
|
||||||
./services/window-managers/river.nix
|
./services/window-managers/i3-sway/swaynag.nix
|
||||||
./services/window-managers/spectrwm.nix
|
./services/window-managers/river.nix
|
||||||
./services/window-managers/wayfire.nix
|
./services/window-managers/spectrwm.nix
|
||||||
./services/window-managers/xmonad.nix
|
./services/window-managers/wayfire.nix
|
||||||
./services/wlsunset.nix
|
./services/window-managers/xmonad.nix
|
||||||
./services/wluma.nix
|
./services/wlsunset.nix
|
||||||
./services/wob.nix
|
./services/wluma.nix
|
||||||
./services/wpaperd.nix
|
./services/wob.nix
|
||||||
./services/xcape.nix
|
./services/wpaperd.nix
|
||||||
./services/xembed-sni-proxy.nix
|
./services/xcape.nix
|
||||||
./services/xidlehook.nix
|
./services/xembed-sni-proxy.nix
|
||||||
./services/xscreensaver.nix
|
./services/xidlehook.nix
|
||||||
./services/xsettingsd.nix
|
./services/xscreensaver.nix
|
||||||
./services/xsuspender.nix
|
./services/xsettingsd.nix
|
||||||
./services/yubikey-agent.nix
|
./services/xsuspender.nix
|
||||||
./systemd.nix
|
./services/yubikey-agent.nix
|
||||||
./targets/darwin
|
./systemd.nix
|
||||||
./targets/generic-linux.nix
|
./targets/darwin
|
||||||
./wayland.nix
|
./targets/generic-linux.nix
|
||||||
./xresources.nix
|
./wayland.nix
|
||||||
./xsession.nix
|
./xresources.nix
|
||||||
./misc/nix.nix
|
./xsession.nix
|
||||||
(pkgs.path + "/nixos/modules/misc/assertions.nix")
|
./misc/nix.nix
|
||||||
(pkgs.path + "/nixos/modules/misc/meta.nix")
|
(pkgs.path + "/nixos/modules/misc/assertions.nix")
|
||||||
|
(pkgs.path + "/nixos/modules/misc/meta.nix")
|
||||||
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "password-store-sync" ] ''
|
(lib.mkRemovedOptionModule [ "services" "password-store-sync" ] ''
|
||||||
Use services.git-sync instead.
|
Use services.git-sync instead.
|
||||||
'')
|
'')
|
||||||
(lib.mkRemovedOptionModule [ "services" "keepassx" ] ''
|
(lib.mkRemovedOptionModule [ "services" "keepassx" ] ''
|
||||||
KeePassX is no longer maintained.
|
KeePassX is no longer maintained.
|
||||||
'')
|
'')
|
||||||
] ++ lib.optional useNixpkgsModule ./misc/nixpkgs.nix
|
]
|
||||||
|
++ lib.optional useNixpkgsModule ./misc/nixpkgs.nix
|
||||||
++ lib.optional (!useNixpkgsModule) ./misc/nixpkgs-disabled.nix;
|
++ lib.optional (!useNixpkgsModule) ./misc/nixpkgs-disabled.nix;
|
||||||
|
|
||||||
pkgsModule = { config, ... }: {
|
pkgsModule =
|
||||||
config = {
|
{ config, ... }:
|
||||||
_module.args.baseModules = modules;
|
{
|
||||||
_module.args.pkgsPath = lib.mkDefault
|
config =
|
||||||
(if lib.versionAtLeast config.home.stateVersion "20.09" then
|
{
|
||||||
pkgs.path
|
_module.args.baseModules = modules;
|
||||||
else
|
_module.args.pkgsPath = lib.mkDefault (
|
||||||
<nixpkgs>);
|
if lib.versionAtLeast config.home.stateVersion "20.09" then pkgs.path else <nixpkgs>
|
||||||
_module.args.pkgs = lib.mkDefault pkgs;
|
);
|
||||||
_module.check = check;
|
_module.args.pkgs = lib.mkDefault pkgs;
|
||||||
lib = lib.hm;
|
_module.check = check;
|
||||||
} // lib.optionalAttrs useNixpkgsModule {
|
lib = lib.hm;
|
||||||
nixpkgs.system = lib.mkDefault pkgs.stdenv.hostPlatform.system;
|
}
|
||||||
|
// lib.optionalAttrs useNixpkgsModule {
|
||||||
|
nixpkgs.system = lib.mkDefault pkgs.stdenv.hostPlatform.system;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
in modules ++ [ pkgsModule ]
|
in
|
||||||
|
modules ++ [ pkgsModule ]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
let cfg = config.programs.abook;
|
config,
|
||||||
in {
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.programs.abook;
|
||||||
|
in
|
||||||
|
{
|
||||||
options.programs.abook = {
|
options.programs.abook = {
|
||||||
enable = lib.mkEnableOption "Abook";
|
enable = lib.mkEnableOption "Abook";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,29 @@
|
||||||
{ config, lib, confSections, confSection, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
confSections,
|
||||||
|
confSection,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) literalExpression mkOption types;
|
inherit (lib) literalExpression mkOption types;
|
||||||
|
|
||||||
mapAttrNames = f: attr:
|
mapAttrNames =
|
||||||
lib.listToAttrs (lib.attrValues (lib.mapAttrs (k: v: {
|
f: attr:
|
||||||
name = f k;
|
lib.listToAttrs (
|
||||||
value = v;
|
lib.attrValues (
|
||||||
}) attr));
|
lib.mapAttrs (k: v: {
|
||||||
|
name = f k;
|
||||||
|
value = v;
|
||||||
|
}) attr
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
addAccountName = name: k: "${k}:account=${name}";
|
addAccountName = name: k: "${k}:account=${name}";
|
||||||
|
|
||||||
oauth2Params = mkOption {
|
oauth2Params = mkOption {
|
||||||
type = with types;
|
type =
|
||||||
|
with types;
|
||||||
nullOr (submodule {
|
nullOr (submodule {
|
||||||
options = {
|
options = {
|
||||||
token_endpoint = mkOption {
|
token_endpoint = mkOption {
|
||||||
|
|
@ -37,7 +49,9 @@ let
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
default = null;
|
default = null;
|
||||||
example = { token_endpoint = "<token_endpoint>"; };
|
example = {
|
||||||
|
token_endpoint = "<token_endpoint>";
|
||||||
|
};
|
||||||
description = ''
|
description = ''
|
||||||
Sets the oauth2 params if authentication mechanism oauthbearer or
|
Sets the oauth2 params if authentication mechanism oauthbearer or
|
||||||
xoauth2 is used.
|
xoauth2 is used.
|
||||||
|
|
@ -45,157 +59,188 @@ let
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
type = mkOption {
|
type = mkOption {
|
||||||
type = types.attrsOf (types.submodule {
|
type = types.attrsOf (
|
||||||
options.aerc = {
|
types.submodule {
|
||||||
enable = lib.mkEnableOption "aerc";
|
options.aerc = {
|
||||||
extraAccounts = mkOption {
|
enable = lib.mkEnableOption "aerc";
|
||||||
type = confSection;
|
extraAccounts = mkOption {
|
||||||
default = { };
|
type = confSection;
|
||||||
example =
|
default = { };
|
||||||
literalExpression ''{ source = "maildir://~/Maildir/example"; }'';
|
example = literalExpression ''{ source = "maildir://~/Maildir/example"; }'';
|
||||||
description = ''
|
description = ''
|
||||||
Extra config added to the configuration section for this account in
|
Extra config added to the configuration section for this account in
|
||||||
{file}`$HOME/.config/aerc/accounts.conf`.
|
{file}`$HOME/.config/aerc/accounts.conf`.
|
||||||
See {manpage}`aerc-accounts(5)`.
|
See {manpage}`aerc-accounts(5)`.
|
||||||
'';
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraBinds = mkOption {
|
||||||
|
type = confSections;
|
||||||
|
default = { };
|
||||||
|
example = literalExpression ''{ messages = { d = ":move ''${folder.trash}<Enter>"; }; }'';
|
||||||
|
description = ''
|
||||||
|
Extra bindings specific to this account, added to
|
||||||
|
{file}`$HOME/.config/aerc/binds.conf`.
|
||||||
|
See {manpage}`aerc-binds(5)`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = confSections;
|
||||||
|
default = { };
|
||||||
|
example = literalExpression "{ ui = { sidebar-width = 25; }; }";
|
||||||
|
description = ''
|
||||||
|
Config specific to this account, added to {file}`$HOME/.config/aerc/aerc.conf`.
|
||||||
|
Aerc only supports per-account UI configuration.
|
||||||
|
For other sections of {file}`$HOME/.config/aerc/aerc.conf`,
|
||||||
|
use `programs.aerc.extraConfig`.
|
||||||
|
See {manpage}`aerc-config(5)`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
imapAuth = mkOption {
|
||||||
|
type =
|
||||||
|
with types;
|
||||||
|
nullOr (enum [
|
||||||
|
"oauthbearer"
|
||||||
|
"xoauth2"
|
||||||
|
]);
|
||||||
|
default = null;
|
||||||
|
example = "auth";
|
||||||
|
description = ''
|
||||||
|
Sets the authentication mechanism if imap is used as the incoming
|
||||||
|
method.
|
||||||
|
See {manpage}`aerc-imap(5)`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
imapOauth2Params = oauth2Params;
|
||||||
|
|
||||||
|
smtpAuth = mkOption {
|
||||||
|
type =
|
||||||
|
with types;
|
||||||
|
nullOr (enum [
|
||||||
|
"none"
|
||||||
|
"plain"
|
||||||
|
"login"
|
||||||
|
"oauthbearer"
|
||||||
|
"xoauth2"
|
||||||
|
]);
|
||||||
|
default = "plain";
|
||||||
|
example = "auth";
|
||||||
|
description = ''
|
||||||
|
Sets the authentication mechanism if smtp is used as the outgoing
|
||||||
|
method.
|
||||||
|
See {manpage}`aerc-smtp(5)`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
smtpOauth2Params = oauth2Params;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
extraBinds = mkOption {
|
);
|
||||||
type = confSections;
|
|
||||||
default = { };
|
|
||||||
example = literalExpression
|
|
||||||
''{ messages = { d = ":move ''${folder.trash}<Enter>"; }; }'';
|
|
||||||
description = ''
|
|
||||||
Extra bindings specific to this account, added to
|
|
||||||
{file}`$HOME/.config/aerc/binds.conf`.
|
|
||||||
See {manpage}`aerc-binds(5)`.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
extraConfig = mkOption {
|
|
||||||
type = confSections;
|
|
||||||
default = { };
|
|
||||||
example = literalExpression "{ ui = { sidebar-width = 25; }; }";
|
|
||||||
description = ''
|
|
||||||
Config specific to this account, added to {file}`$HOME/.config/aerc/aerc.conf`.
|
|
||||||
Aerc only supports per-account UI configuration.
|
|
||||||
For other sections of {file}`$HOME/.config/aerc/aerc.conf`,
|
|
||||||
use `programs.aerc.extraConfig`.
|
|
||||||
See {manpage}`aerc-config(5)`.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
imapAuth = mkOption {
|
|
||||||
type = with types; nullOr (enum [ "oauthbearer" "xoauth2" ]);
|
|
||||||
default = null;
|
|
||||||
example = "auth";
|
|
||||||
description = ''
|
|
||||||
Sets the authentication mechanism if imap is used as the incoming
|
|
||||||
method.
|
|
||||||
See {manpage}`aerc-imap(5)`.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
imapOauth2Params = oauth2Params;
|
|
||||||
|
|
||||||
smtpAuth = mkOption {
|
|
||||||
type = with types;
|
|
||||||
nullOr (enum [ "none" "plain" "login" "oauthbearer" "xoauth2" ]);
|
|
||||||
default = "plain";
|
|
||||||
example = "auth";
|
|
||||||
description = ''
|
|
||||||
Sets the authentication mechanism if smtp is used as the outgoing
|
|
||||||
method.
|
|
||||||
See {manpage}`aerc-smtp(5)`.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
smtpOauth2Params = oauth2Params;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mkAccount = name: account:
|
mkAccount =
|
||||||
|
name: account:
|
||||||
let
|
let
|
||||||
nullOrMap = f: v: if v == null then v else f v;
|
nullOrMap = f: v: if v == null then v else f v;
|
||||||
|
|
||||||
optPort = port: if port != null then ":${toString port}" else "";
|
optPort = port: if port != null then ":${toString port}" else "";
|
||||||
|
|
||||||
optAttr = k: v:
|
optAttr = k: v: if v != null && v != [ ] && v != "" then { ${k} = v; } else { };
|
||||||
if v != null && v != [ ] && v != "" then { ${k} = v; } else { };
|
|
||||||
|
|
||||||
optPwCmd = k: p:
|
optPwCmd = k: p: optAttr "${k}-cred-cmd" (nullOrMap (lib.concatStringsSep " ") p);
|
||||||
optAttr "${k}-cred-cmd" (nullOrMap (lib.concatStringsSep " ") p);
|
|
||||||
|
|
||||||
useOauth = auth: builtins.elem auth [ "oauthbearer" "xoauth2" ];
|
useOauth =
|
||||||
|
auth:
|
||||||
|
builtins.elem auth [
|
||||||
|
"oauthbearer"
|
||||||
|
"xoauth2"
|
||||||
|
];
|
||||||
|
|
||||||
oauthParams = { auth, params }:
|
oauthParams =
|
||||||
|
{ auth, params }:
|
||||||
if useOauth auth && params != null && params != { } then
|
if useOauth auth && params != null && params != { } then
|
||||||
"?" + builtins.concatStringsSep "&"
|
"?"
|
||||||
(lib.attrsets.mapAttrsToList (k: v: k + "=" + lib.strings.escapeURL v)
|
+ builtins.concatStringsSep "&" (
|
||||||
(lib.attrsets.filterAttrs (k: v: v != null) params))
|
lib.attrsets.mapAttrsToList (k: v: k + "=" + lib.strings.escapeURL v) (
|
||||||
|
lib.attrsets.filterAttrs (k: v: v != null) params
|
||||||
|
)
|
||||||
|
)
|
||||||
else
|
else
|
||||||
"";
|
"";
|
||||||
|
|
||||||
mkConfig = {
|
mkConfig = {
|
||||||
maildir = cfg: {
|
maildir = cfg: {
|
||||||
source =
|
source = "maildir://${config.accounts.email.maildirBasePath}/${cfg.maildir.path}";
|
||||||
"maildir://${config.accounts.email.maildirBasePath}/${cfg.maildir.path}";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
maildirpp = cfg: {
|
maildirpp = cfg: {
|
||||||
source =
|
source = "maildirpp://${config.accounts.email.maildirBasePath}/${cfg.maildir.path}/Inbox";
|
||||||
"maildirpp://${config.accounts.email.maildirBasePath}/${cfg.maildir.path}/Inbox";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
imap = { userName, imap, passwordCommand, aerc, ... }@cfg:
|
imap =
|
||||||
|
{
|
||||||
|
userName,
|
||||||
|
imap,
|
||||||
|
passwordCommand,
|
||||||
|
aerc,
|
||||||
|
...
|
||||||
|
}@cfg:
|
||||||
let
|
let
|
||||||
loginMethod' =
|
loginMethod' = if cfg.aerc.imapAuth != null then "+${cfg.aerc.imapAuth}" else "";
|
||||||
if cfg.aerc.imapAuth != null then "+${cfg.aerc.imapAuth}" else "";
|
|
||||||
|
|
||||||
oauthParams' = oauthParams {
|
oauthParams' = oauthParams {
|
||||||
auth = cfg.aerc.imapAuth;
|
auth = cfg.aerc.imapAuth;
|
||||||
params = cfg.aerc.imapOauth2Params;
|
params = cfg.aerc.imapOauth2Params;
|
||||||
};
|
};
|
||||||
|
|
||||||
protocol = if imap.tls.enable then
|
protocol =
|
||||||
if imap.tls.useStartTls then "imap" else "imaps${loginMethod'}"
|
if imap.tls.enable then
|
||||||
else
|
if imap.tls.useStartTls then "imap" else "imaps${loginMethod'}"
|
||||||
"imap+insecure";
|
else
|
||||||
|
"imap+insecure";
|
||||||
|
|
||||||
port' = optPort imap.port;
|
port' = optPort imap.port;
|
||||||
|
|
||||||
in {
|
in
|
||||||
source =
|
{
|
||||||
"${protocol}://${userName}@${imap.host}${port'}${oauthParams'}";
|
source = "${protocol}://${userName}@${imap.host}${port'}${oauthParams'}";
|
||||||
} // optPwCmd "source" passwordCommand;
|
}
|
||||||
|
// optPwCmd "source" passwordCommand;
|
||||||
|
|
||||||
smtp = { userName, smtp, passwordCommand, ... }@cfg:
|
smtp =
|
||||||
|
{
|
||||||
|
userName,
|
||||||
|
smtp,
|
||||||
|
passwordCommand,
|
||||||
|
...
|
||||||
|
}@cfg:
|
||||||
let
|
let
|
||||||
loginMethod' =
|
loginMethod' = if cfg.aerc.smtpAuth != null then "+${cfg.aerc.smtpAuth}" else "";
|
||||||
if cfg.aerc.smtpAuth != null then "+${cfg.aerc.smtpAuth}" else "";
|
|
||||||
|
|
||||||
oauthParams' = oauthParams {
|
oauthParams' = oauthParams {
|
||||||
auth = cfg.aerc.smtpAuth;
|
auth = cfg.aerc.smtpAuth;
|
||||||
params = cfg.aerc.smtpOauth2Params;
|
params = cfg.aerc.smtpOauth2Params;
|
||||||
};
|
};
|
||||||
|
|
||||||
protocol = if smtp.tls.enable then
|
protocol =
|
||||||
if smtp.tls.useStartTls then
|
if smtp.tls.enable then
|
||||||
"smtp${loginMethod'}"
|
if smtp.tls.useStartTls then "smtp${loginMethod'}" else "smtps${loginMethod'}"
|
||||||
else
|
else
|
||||||
"smtps${loginMethod'}"
|
"smtp+insecure${loginMethod'}";
|
||||||
else
|
|
||||||
"smtp+insecure${loginMethod'}";
|
|
||||||
|
|
||||||
port' = optPort smtp.port;
|
port' = optPort smtp.port;
|
||||||
|
|
||||||
in {
|
in
|
||||||
outgoing =
|
{
|
||||||
"${protocol}://${userName}@${smtp.host}${port'}${oauthParams'}";
|
outgoing = "${protocol}://${userName}@${smtp.host}${port'}${oauthParams'}";
|
||||||
} // optPwCmd "outgoing" passwordCommand;
|
}
|
||||||
|
// optPwCmd "outgoing" passwordCommand;
|
||||||
|
|
||||||
msmtp = cfg: {
|
msmtp = cfg: {
|
||||||
outgoing = "msmtpq --read-envelope-from --read-recipients";
|
outgoing = "msmtpq --read-envelope-from --read-recipients";
|
||||||
|
|
@ -203,17 +248,21 @@ in {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
basicCfg = account:
|
basicCfg =
|
||||||
|
account:
|
||||||
{
|
{
|
||||||
from = "${account.realName} <${account.address}>";
|
from = "${account.realName} <${account.address}>";
|
||||||
} // (optAttr "copy-to" account.folders.sent)
|
}
|
||||||
|
// (optAttr "copy-to" account.folders.sent)
|
||||||
// (optAttr "default" account.folders.inbox)
|
// (optAttr "default" account.folders.inbox)
|
||||||
// (optAttr "postpone" account.folders.drafts)
|
// (optAttr "postpone" account.folders.drafts)
|
||||||
// (optAttr "aliases" account.aliases);
|
// (optAttr "aliases" account.aliases);
|
||||||
|
|
||||||
sourceCfg = account:
|
sourceCfg =
|
||||||
if account.mbsync.enable && account.mbsync.flatten == null
|
account:
|
||||||
&& account.mbsync.subFolders == "Maildir++" then
|
if
|
||||||
|
account.mbsync.enable && account.mbsync.flatten == null && account.mbsync.subFolders == "Maildir++"
|
||||||
|
then
|
||||||
mkConfig.maildirpp account
|
mkConfig.maildirpp account
|
||||||
else if account.mbsync.enable || account.offlineimap.enable then
|
else if account.mbsync.enable || account.offlineimap.enable then
|
||||||
mkConfig.maildir account
|
mkConfig.maildir account
|
||||||
|
|
@ -222,7 +271,8 @@ in {
|
||||||
else
|
else
|
||||||
{ };
|
{ };
|
||||||
|
|
||||||
outgoingCfg = account:
|
outgoingCfg =
|
||||||
|
account:
|
||||||
if account.msmtp.enable then
|
if account.msmtp.enable then
|
||||||
mkConfig.msmtp account
|
mkConfig.msmtp account
|
||||||
else if account.smtp != null then
|
else if account.smtp != null then
|
||||||
|
|
@ -230,19 +280,22 @@ in {
|
||||||
else
|
else
|
||||||
{ };
|
{ };
|
||||||
|
|
||||||
gpgCfg = account:
|
gpgCfg =
|
||||||
|
account:
|
||||||
lib.optionalAttrs (account.gpg != null) {
|
lib.optionalAttrs (account.gpg != null) {
|
||||||
pgp-key-id = account.gpg.key;
|
pgp-key-id = account.gpg.key;
|
||||||
pgp-auto-sign = account.gpg.signByDefault;
|
pgp-auto-sign = account.gpg.signByDefault;
|
||||||
pgp-opportunistic-encrypt = account.gpg.encryptByDefault;
|
pgp-opportunistic-encrypt = account.gpg.encryptByDefault;
|
||||||
};
|
};
|
||||||
|
|
||||||
in (basicCfg account) // (sourceCfg account) // (outgoingCfg account)
|
in
|
||||||
// (gpgCfg account) // account.aerc.extraAccounts;
|
(basicCfg account)
|
||||||
|
// (sourceCfg account)
|
||||||
|
// (outgoingCfg account)
|
||||||
|
// (gpgCfg account)
|
||||||
|
// account.aerc.extraAccounts;
|
||||||
|
|
||||||
mkAccountConfig = name: account:
|
mkAccountConfig = name: account: mapAttrNames (addAccountName name) account.aerc.extraConfig;
|
||||||
mapAttrNames (addAccountName name) account.aerc.extraConfig;
|
|
||||||
|
|
||||||
mkAccountBinds = name: account:
|
mkAccountBinds = name: account: mapAttrNames (addAccountName name) account.aerc.extraBinds;
|
||||||
mapAttrNames (addAccountName name) account.aerc.extraBinds;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,34 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
attrsets generators literalExpression mapAttrs mkIf mkOption types;
|
attrsets
|
||||||
|
generators
|
||||||
|
literalExpression
|
||||||
|
mapAttrs
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.programs.aerc;
|
cfg = config.programs.aerc;
|
||||||
|
|
||||||
primitive = with types;
|
primitive =
|
||||||
((type: either type (listOf type)) (nullOr (oneOf [ str int bool float ])))
|
with types;
|
||||||
|
((type: either type (listOf type)) (
|
||||||
|
nullOr (oneOf [
|
||||||
|
str
|
||||||
|
int
|
||||||
|
bool
|
||||||
|
float
|
||||||
|
])
|
||||||
|
))
|
||||||
// {
|
// {
|
||||||
description =
|
description = "values (null, bool, int, string, or float) or a list of values, that will be joined with a comma";
|
||||||
"values (null, bool, int, string, or float) or a list of values, that will be joined with a comma";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
confSection = types.attrsOf primitive;
|
confSection = types.attrsOf primitive;
|
||||||
|
|
@ -19,18 +38,25 @@ let
|
||||||
sectionsOrLines = types.either types.lines confSections;
|
sectionsOrLines = types.either types.lines confSections;
|
||||||
|
|
||||||
accounts = import ./aerc-accounts.nix {
|
accounts = import ./aerc-accounts.nix {
|
||||||
inherit config pkgs lib confSection confSections;
|
inherit
|
||||||
|
config
|
||||||
|
pkgs
|
||||||
|
lib
|
||||||
|
confSection
|
||||||
|
confSections
|
||||||
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
aerc-accounts =
|
aerc-accounts = attrsets.filterAttrs (_: v: v.aerc.enable) config.accounts.email.accounts;
|
||||||
attrsets.filterAttrs (_: v: v.aerc.enable) config.accounts.email.accounts;
|
|
||||||
|
|
||||||
configDir = if (pkgs.stdenv.isDarwin && !config.xdg.enable) then
|
configDir =
|
||||||
"Library/Preferences/aerc"
|
if (pkgs.stdenv.isDarwin && !config.xdg.enable) then
|
||||||
else
|
"Library/Preferences/aerc"
|
||||||
"${config.xdg.configHome}/aerc";
|
else
|
||||||
|
"${config.xdg.configHome}/aerc";
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = with lib.hm.maintainers; [ lukasngl ];
|
meta.maintainers = with lib.hm.maintainers; [ lukasngl ];
|
||||||
|
|
||||||
options.accounts.email.accounts = accounts.type;
|
options.accounts.email.accounts = accounts.type;
|
||||||
|
|
@ -44,8 +70,7 @@ in {
|
||||||
extraAccounts = mkOption {
|
extraAccounts = mkOption {
|
||||||
type = sectionsOrLines;
|
type = sectionsOrLines;
|
||||||
default = { };
|
default = { };
|
||||||
example = literalExpression
|
example = literalExpression ''{ Work = { source = "maildir://~/Maildir/work"; }; }'';
|
||||||
''{ Work = { source = "maildir://~/Maildir/work"; }; }'';
|
|
||||||
description = ''
|
description = ''
|
||||||
Extra lines added to {file}`$HOME/.config/aerc/accounts.conf`.
|
Extra lines added to {file}`$HOME/.config/aerc/accounts.conf`.
|
||||||
|
|
||||||
|
|
@ -103,127 +128,151 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let
|
config =
|
||||||
joinCfg = cfgs: lib.concatStringsSep "\n" (lib.filter (v: v != "") cfgs);
|
let
|
||||||
|
joinCfg = cfgs: lib.concatStringsSep "\n" (lib.filter (v: v != "") cfgs);
|
||||||
|
|
||||||
toINI = conf: # quirk: global section is prepended w/o section heading
|
toINI =
|
||||||
let
|
conf: # quirk: global section is prepended w/o section heading
|
||||||
global = conf.global or { };
|
let
|
||||||
local = removeAttrs conf [ "global" ];
|
global = conf.global or { };
|
||||||
mkValueString = v:
|
local = removeAttrs conf [ "global" ];
|
||||||
if lib.isList v then # join with comma
|
mkValueString =
|
||||||
lib.concatStringsSep ","
|
v:
|
||||||
(map (generators.mkValueStringDefault { }) v)
|
if lib.isList v then # join with comma
|
||||||
else
|
lib.concatStringsSep "," (map (generators.mkValueStringDefault { }) v)
|
||||||
generators.mkValueStringDefault { } v;
|
else
|
||||||
mkKeyValue =
|
generators.mkValueStringDefault { } v;
|
||||||
generators.mkKeyValueDefault { inherit mkValueString; } " = ";
|
mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } " = ";
|
||||||
in joinCfg [
|
in
|
||||||
(generators.toKeyValue { inherit mkKeyValue; } global)
|
joinCfg [
|
||||||
(generators.toINI { inherit mkKeyValue; } local)
|
(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
|
||||||
|
{
|
||||||
|
name = "${configDir}/stylesets/${k}";
|
||||||
|
value.text = joinCfg [
|
||||||
|
header
|
||||||
|
value
|
||||||
|
];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
primaryAccountAccounts = mapAttrs accounts.mkAccount primaryAccount;
|
||||||
|
|
||||||
|
accountsExtraAccounts = mapAttrs accounts.mkAccount otherAccounts;
|
||||||
|
|
||||||
|
accountsExtraConfig = mapAttrs accounts.mkAccountConfig aerc-accounts;
|
||||||
|
|
||||||
|
accountsExtraBinds = mapAttrs accounts.mkAccountBinds aerc-accounts;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
genAccountsConf = (
|
||||||
|
(cfg.extraAccounts != "" && cfg.extraAccounts != { })
|
||||||
|
|| !(isRecursivelyEmpty accountsExtraAccounts)
|
||||||
|
|| !(isRecursivelyEmpty primaryAccountAccounts)
|
||||||
|
);
|
||||||
|
|
||||||
|
genAercConf = (
|
||||||
|
(cfg.extraConfig != "" && cfg.extraConfig != { }) || !(isRecursivelyEmpty accountsExtraConfig)
|
||||||
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
[
|
||||||
|
''
|
||||||
|
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).
|
||||||
|
> Set this option to true to ignore this permission check. Use this with care as it may expose your credentials.
|
||||||
|
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
|
||||||
|
[ ];
|
||||||
|
|
||||||
|
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.
|
||||||
|
'';
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
mkINI = conf: if lib.isString conf then conf else toINI conf;
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
|
|
||||||
mkStyleset = attrsets.mapAttrs' (k: v:
|
home.file =
|
||||||
let value = if lib.isString v then v else toINI { global = v; };
|
{
|
||||||
in {
|
"${configDir}/accounts.conf" = mkIf genAccountsConf {
|
||||||
name = "${configDir}/stylesets/${k}";
|
text = joinCfg [
|
||||||
value.text = joinCfg [ header value ];
|
header
|
||||||
});
|
(mkINI cfg.extraAccounts)
|
||||||
|
(mkINI primaryAccountAccounts)
|
||||||
|
(mkINI accountsExtraAccounts)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
mkTemplates = attrsets.mapAttrs' (k: v: {
|
"${configDir}/aerc.conf" = mkIf genAercConf {
|
||||||
name = "${configDir}/templates/${k}";
|
text = joinCfg [
|
||||||
value.text = v;
|
header
|
||||||
});
|
(mkINI cfg.extraConfig)
|
||||||
|
(joinContextual accountsExtraConfig)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
primaryAccount = attrsets.filterAttrs (_: v: v.primary) aerc-accounts;
|
"${configDir}/binds.conf" = mkIf genBindsConf {
|
||||||
otherAccounts = attrsets.filterAttrs (_: v: !v.primary) aerc-accounts;
|
text = joinCfg [
|
||||||
|
header
|
||||||
primaryAccountAccounts = mapAttrs accounts.mkAccount primaryAccount;
|
(mkINI cfg.extraBinds)
|
||||||
|
(joinContextual accountsExtraBinds)
|
||||||
accountsExtraAccounts = mapAttrs accounts.mkAccount otherAccounts;
|
];
|
||||||
|
};
|
||||||
accountsExtraConfig = mapAttrs accounts.mkAccountConfig aerc-accounts;
|
}
|
||||||
|
// (mkStyleset cfg.stylesets)
|
||||||
accountsExtraBinds = mapAttrs accounts.mkAccountBinds aerc-accounts;
|
// (mkTemplates cfg.templates);
|
||||||
|
};
|
||||||
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;
|
|
||||||
|
|
||||||
genAccountsConf = ((cfg.extraAccounts != "" && cfg.extraAccounts != { })
|
|
||||||
|| !(isRecursivelyEmpty accountsExtraAccounts)
|
|
||||||
|| !(isRecursivelyEmpty primaryAccountAccounts));
|
|
||||||
|
|
||||||
genAercConf = ((cfg.extraConfig != "" && cfg.extraConfig != { })
|
|
||||||
|| !(isRecursivelyEmpty accountsExtraConfig));
|
|
||||||
|
|
||||||
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 [''
|
|
||||||
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).
|
|
||||||
> Set this option to true to ignore this permission check. Use this with care as it may expose your credentials.
|
|
||||||
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
|
|
||||||
[ ];
|
|
||||||
|
|
||||||
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 = {
|
|
||||||
"${configDir}/accounts.conf" = mkIf genAccountsConf {
|
|
||||||
text = joinCfg [
|
|
||||||
header
|
|
||||||
(mkINI cfg.extraAccounts)
|
|
||||||
(mkINI primaryAccountAccounts)
|
|
||||||
(mkINI accountsExtraAccounts)
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
"${configDir}/aerc.conf" = mkIf genAercConf {
|
|
||||||
text = joinCfg [
|
|
||||||
header
|
|
||||||
(mkINI cfg.extraConfig)
|
|
||||||
(joinContextual accountsExtraConfig)
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
"${configDir}/binds.conf" = mkIf genBindsConf {
|
|
||||||
text = joinCfg [
|
|
||||||
header
|
|
||||||
(mkINI cfg.extraBinds)
|
|
||||||
(joinContextual accountsExtraBinds)
|
|
||||||
];
|
|
||||||
};
|
|
||||||
} // (mkStyleset cfg.stylesets) // (mkTemplates cfg.templates);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types;
|
||||||
cfg = config.programs.aerospace;
|
cfg = config.programs.aerospace;
|
||||||
|
|
@ -6,22 +11,29 @@ let
|
||||||
tomlFormat = pkgs.formats.toml { };
|
tomlFormat = pkgs.formats.toml { };
|
||||||
|
|
||||||
# filterAttrsRecursive supporting lists, as well.
|
# filterAttrsRecursive supporting lists, as well.
|
||||||
filterListAndAttrsRecursive = pred: set:
|
filterListAndAttrsRecursive =
|
||||||
lib.listToAttrs (lib.concatMap (name:
|
pred: set:
|
||||||
let v = set.${name};
|
lib.listToAttrs (
|
||||||
in if pred v then
|
lib.concatMap (
|
||||||
[
|
name:
|
||||||
(lib.nameValuePair name (if lib.isAttrs v then
|
let
|
||||||
filterListAndAttrsRecursive pred v
|
v = set.${name};
|
||||||
else if lib.isList v then
|
in
|
||||||
(map (i:
|
if pred v then
|
||||||
if lib.isAttrs i then filterListAndAttrsRecursive pred i else i)
|
[
|
||||||
(lib.filter pred v))
|
(lib.nameValuePair name (
|
||||||
else
|
if lib.isAttrs v then
|
||||||
v))
|
filterListAndAttrsRecursive pred v
|
||||||
]
|
else if lib.isList v then
|
||||||
else
|
(map (i: if lib.isAttrs i then filterListAndAttrsRecursive pred i else i) (lib.filter pred v))
|
||||||
[ ]) (lib.attrNames set));
|
else
|
||||||
|
v
|
||||||
|
))
|
||||||
|
]
|
||||||
|
else
|
||||||
|
[ ]
|
||||||
|
) (lib.attrNames set)
|
||||||
|
);
|
||||||
filterNulls = filterListAndAttrsRecursive (v: v != null);
|
filterNulls = filterListAndAttrsRecursive (v: v != null);
|
||||||
|
|
||||||
# Turns
|
# Turns
|
||||||
|
|
@ -30,16 +42,22 @@ let
|
||||||
# {"if.foo" = "xxx"; "if.bar" = "yyy"}
|
# {"if.foo" = "xxx"; "if.bar" = "yyy"}
|
||||||
# so that the correct TOML is generated for the
|
# so that the correct TOML is generated for the
|
||||||
# on-window-detected table.
|
# on-window-detected table.
|
||||||
flattenConditions = attrs:
|
flattenConditions =
|
||||||
let conditions = attrs."if" or { };
|
attrs:
|
||||||
in builtins.removeAttrs attrs [ "if" ]
|
let
|
||||||
// lib.concatMapAttrs (n: v: { "if.${n}" = v; }) conditions;
|
conditions = attrs."if" or { };
|
||||||
|
in
|
||||||
|
builtins.removeAttrs attrs [ "if" ] // lib.concatMapAttrs (n: v: { "if.${n}" = v; }) conditions;
|
||||||
|
|
||||||
flattenOnWindowDetected = cfg:
|
flattenOnWindowDetected =
|
||||||
let owd = cfg.on-window-detected or [ ];
|
cfg:
|
||||||
in cfg // { on-window-detected = map flattenConditions owd; };
|
let
|
||||||
|
owd = cfg.on-window-detected or [ ];
|
||||||
|
in
|
||||||
|
cfg // { on-window-detected = map flattenConditions owd; };
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = with lib.hm.maintainers; [ damidoug ];
|
meta.maintainers = with lib.hm.maintainers; [ damidoug ];
|
||||||
|
|
||||||
options.programs.aerospace = {
|
options.programs.aerospace = {
|
||||||
|
|
@ -76,102 +94,122 @@ in {
|
||||||
enable-normalization-flatten-containers = mkOption {
|
enable-normalization-flatten-containers = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
description =
|
description = ''Containers that have only one child are "flattened".'';
|
||||||
''Containers that have only one child are "flattened".'';
|
};
|
||||||
|
enable-normalization-opposite-orientation-for-nested-containers = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Containers that nest into each other must have opposite orientations.";
|
||||||
};
|
};
|
||||||
enable-normalization-opposite-orientation-for-nested-containers =
|
|
||||||
mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description =
|
|
||||||
"Containers that nest into each other must have opposite orientations.";
|
|
||||||
};
|
|
||||||
accordion-padding = mkOption {
|
accordion-padding = mkOption {
|
||||||
type = types.int;
|
type = types.int;
|
||||||
default = 30;
|
default = 30;
|
||||||
description = "Padding between windows in an accordion container.";
|
description = "Padding between windows in an accordion container.";
|
||||||
};
|
};
|
||||||
default-root-container-layout = mkOption {
|
default-root-container-layout = mkOption {
|
||||||
type = types.enum [ "tiles" "accordion" ];
|
type = types.enum [
|
||||||
|
"tiles"
|
||||||
|
"accordion"
|
||||||
|
];
|
||||||
default = "tiles";
|
default = "tiles";
|
||||||
description = "Default layout for the root container.";
|
description = "Default layout for the root container.";
|
||||||
};
|
};
|
||||||
default-root-container-orientation = mkOption {
|
default-root-container-orientation = mkOption {
|
||||||
type = types.enum [ "horizontal" "vertical" "auto" ];
|
type = types.enum [
|
||||||
|
"horizontal"
|
||||||
|
"vertical"
|
||||||
|
"auto"
|
||||||
|
];
|
||||||
default = "auto";
|
default = "auto";
|
||||||
description = "Default orientation for the root container.";
|
description = "Default orientation for the root container.";
|
||||||
};
|
};
|
||||||
on-window-detected = mkOption {
|
on-window-detected = mkOption {
|
||||||
type = types.listOf (types.submodule {
|
type = types.listOf (
|
||||||
options = {
|
types.submodule {
|
||||||
"if" = mkOption {
|
options = {
|
||||||
type = types.submodule {
|
"if" = mkOption {
|
||||||
options = {
|
type = types.submodule {
|
||||||
app-id = mkOption {
|
options = {
|
||||||
type = with types; nullOr str;
|
app-id = mkOption {
|
||||||
default = null;
|
type = with types; nullOr str;
|
||||||
description = "The application ID to match (optional).";
|
default = null;
|
||||||
};
|
description = "The application ID to match (optional).";
|
||||||
workspace = mkOption {
|
};
|
||||||
type = with types; nullOr str;
|
workspace = mkOption {
|
||||||
default = null;
|
type = with types; nullOr str;
|
||||||
description = "The workspace name to match (optional).";
|
default = null;
|
||||||
};
|
description = "The workspace name to match (optional).";
|
||||||
window-title-regex-substring = mkOption {
|
};
|
||||||
type = with types; nullOr str;
|
window-title-regex-substring = mkOption {
|
||||||
default = null;
|
type = with types; nullOr str;
|
||||||
description =
|
default = null;
|
||||||
"Substring to match in the window title (optional).";
|
description = "Substring to match in the window title (optional).";
|
||||||
};
|
};
|
||||||
app-name-regex-substring = mkOption {
|
app-name-regex-substring = mkOption {
|
||||||
type = with types; nullOr str;
|
type = with types; nullOr str;
|
||||||
default = null;
|
default = null;
|
||||||
description =
|
description = "Regex substring to match the app name (optional).";
|
||||||
"Regex substring to match the app name (optional).";
|
};
|
||||||
};
|
during-aerospace-startup = mkOption {
|
||||||
during-aerospace-startup = mkOption {
|
type = with types; nullOr bool;
|
||||||
type = with types; nullOr bool;
|
default = null;
|
||||||
default = null;
|
description = "Whether to match during aerospace startup (optional).";
|
||||||
description =
|
};
|
||||||
"Whether to match during aerospace startup (optional).";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
default = { };
|
||||||
|
description = "Conditions for detecting a window.";
|
||||||
|
};
|
||||||
|
check-further-callbacks = mkOption {
|
||||||
|
type = with types; nullOr bool;
|
||||||
|
default = null;
|
||||||
|
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).";
|
||||||
};
|
};
|
||||||
default = { };
|
|
||||||
description = "Conditions for detecting a window.";
|
|
||||||
};
|
};
|
||||||
check-further-callbacks = mkOption {
|
}
|
||||||
type = with types; nullOr bool;
|
);
|
||||||
default = null;
|
|
||||||
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).";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
});
|
|
||||||
default = [ ];
|
default = [ ];
|
||||||
example = [{
|
example = [
|
||||||
"if" = {
|
{
|
||||||
app-id = "Another.Cool.App";
|
"if" = {
|
||||||
workspace = "cool-workspace";
|
app-id = "Another.Cool.App";
|
||||||
window-title-regex-substring = "Title";
|
workspace = "cool-workspace";
|
||||||
app-name-regex-substring = "CoolApp";
|
window-title-regex-substring = "Title";
|
||||||
during-aerospace-startup = false;
|
app-name-regex-substring = "CoolApp";
|
||||||
};
|
during-aerospace-startup = false;
|
||||||
check-further-callbacks = false;
|
};
|
||||||
run = [ "move-node-to-workspace m" "resize-node" ];
|
check-further-callbacks = false;
|
||||||
}];
|
run = [
|
||||||
description =
|
"move-node-to-workspace m"
|
||||||
"Commands to run every time a new window is detected with optional conditions.";
|
"resize-node"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
description = "Commands to run every time a new window is detected with optional conditions.";
|
||||||
};
|
};
|
||||||
workspace-to-monitor-force-assignment = mkOption {
|
workspace-to-monitor-force-assignment = mkOption {
|
||||||
type = with types;
|
type =
|
||||||
nullOr (attrsOf (oneOf [ int str (listOf str) ]));
|
with types;
|
||||||
|
nullOr (
|
||||||
|
attrsOf (oneOf [
|
||||||
|
int
|
||||||
|
str
|
||||||
|
(listOf str)
|
||||||
|
])
|
||||||
|
);
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
Map workspaces to specific monitors.
|
Map workspaces to specific monitors.
|
||||||
|
|
@ -182,17 +220,18 @@ in {
|
||||||
"2" = "main"; # Main monitor.
|
"2" = "main"; # Main monitor.
|
||||||
"3" = "secondary"; # Secondary monitor (non-main).
|
"3" = "secondary"; # Secondary monitor (non-main).
|
||||||
"4" = "built-in"; # Built-in display.
|
"4" = "built-in"; # Built-in display.
|
||||||
"5" =
|
"5" = "^built-in retina display$"; # Regex for the built-in retina display.
|
||||||
"^built-in retina display$"; # Regex for the built-in retina display.
|
"6" = [
|
||||||
"6" = [ "secondary" "dell" ]; # Match first pattern in the list.
|
"secondary"
|
||||||
|
"dell"
|
||||||
|
]; # Match first pattern in the list.
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
on-focus-changed = mkOption {
|
on-focus-changed = mkOption {
|
||||||
type = with types; listOf str;
|
type = with types; listOf str;
|
||||||
default = [ ];
|
default = [ ];
|
||||||
example = [ "move-mouse monitor-lazy-center" ];
|
example = [ "move-mouse monitor-lazy-center" ];
|
||||||
description =
|
description = "Commands to run every time focused window or workspace changes.";
|
||||||
"Commands to run every time focused window or workspace changes.";
|
|
||||||
};
|
};
|
||||||
on-focused-monitor-changed = mkOption {
|
on-focused-monitor-changed = mkOption {
|
||||||
type = with types; listOf str;
|
type = with types; listOf str;
|
||||||
|
|
@ -210,7 +249,10 @@ in {
|
||||||
description = "Commands to run every time workspace changes.";
|
description = "Commands to run every time workspace changes.";
|
||||||
};
|
};
|
||||||
key-mapping.preset = mkOption {
|
key-mapping.preset = mkOption {
|
||||||
type = types.enum [ "qwerty" "dvorak" ];
|
type = types.enum [
|
||||||
|
"qwerty"
|
||||||
|
"dvorak"
|
||||||
|
];
|
||||||
default = "qwerty";
|
default = "qwerty";
|
||||||
description = "Keymapping preset.";
|
description = "Keymapping preset.";
|
||||||
};
|
};
|
||||||
|
|
@ -243,15 +285,14 @@ in {
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
assertions = [
|
assertions = [
|
||||||
(lib.hm.assertions.assertPlatform "programs.aerospace" pkgs
|
(lib.hm.assertions.assertPlatform "programs.aerospace" pkgs lib.platforms.darwin)
|
||||||
lib.platforms.darwin)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
home = {
|
home = {
|
||||||
packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
file.".config/aerospace/aerospace.toml".source =
|
file.".config/aerospace/aerospace.toml".source = tomlFormat.generate "aerospace" (
|
||||||
tomlFormat.generate "aerospace"
|
filterNulls (flattenOnWindowDetected cfg.userSettings)
|
||||||
(filterNulls (flattenOnWindowDetected cfg.userSettings));
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
let cfg = config.programs.afew;
|
config,
|
||||||
in {
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.programs.afew;
|
||||||
|
in
|
||||||
|
{
|
||||||
options.programs.afew = {
|
options.programs.afew = {
|
||||||
enable = lib.mkEnableOption "the afew initial tagging script for Notmuch";
|
enable = lib.mkEnableOption "the afew initial tagging script for Notmuch";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
cfg = config.programs.alacritty;
|
cfg = config.programs.alacritty;
|
||||||
tomlFormat = pkgs.formats.toml { };
|
tomlFormat = pkgs.formats.toml { };
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
programs.alacritty = {
|
programs.alacritty = {
|
||||||
enable = lib.mkEnableOption "Alacritty";
|
enable = lib.mkEnableOption "Alacritty";
|
||||||
|
|
@ -56,40 +62,45 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
assertions = [{
|
assertions = [
|
||||||
# If using the theme option, ensure that theme exists in the
|
{
|
||||||
# alacritty-theme package.
|
# If using the theme option, ensure that theme exists in the
|
||||||
assertion = let
|
# alacritty-theme package.
|
||||||
available = lib.pipe "${pkgs.alacritty-theme}/share/alacritty-theme" [
|
assertion =
|
||||||
builtins.readDir
|
let
|
||||||
(lib.filterAttrs
|
available = lib.pipe "${pkgs.alacritty-theme}/share/alacritty-theme" [
|
||||||
(name: type: type == "regular" && lib.hasSuffix ".toml" name))
|
builtins.readDir
|
||||||
lib.attrNames
|
(lib.filterAttrs (name: type: type == "regular" && lib.hasSuffix ".toml" name))
|
||||||
(lib.map (lib.removeSuffix ".toml"))
|
lib.attrNames
|
||||||
];
|
(lib.map (lib.removeSuffix ".toml"))
|
||||||
in cfg.theme == null || (builtins.elem cfg.theme available);
|
];
|
||||||
message = "The alacritty theme '${cfg.theme}' does not exist.";
|
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 ];
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
|
|
||||||
programs.alacritty.settings = let
|
programs.alacritty.settings =
|
||||||
theme = "${pkgs.alacritty-theme}/share/alacritty-theme/${cfg.theme}.toml";
|
let
|
||||||
in lib.mkIf (cfg.theme != null) {
|
theme = "${pkgs.alacritty-theme}/share/alacritty-theme/${cfg.theme}.toml";
|
||||||
general.import =
|
in
|
||||||
lib.mkIf (lib.versionAtLeast cfg.package.version "0.14") [ theme ];
|
lib.mkIf (cfg.theme != null) {
|
||||||
import = lib.mkIf (lib.versionOlder cfg.package.version "0.14") [ theme ];
|
general.import = lib.mkIf (lib.versionAtLeast cfg.package.version "0.14") [ theme ];
|
||||||
};
|
import = lib.mkIf (lib.versionOlder cfg.package.version "0.14") [ theme ];
|
||||||
|
};
|
||||||
|
|
||||||
xdg.configFile."alacritty/alacritty.toml" = lib.mkIf (cfg.settings != { }) {
|
xdg.configFile."alacritty/alacritty.toml" = lib.mkIf (cfg.settings != { }) {
|
||||||
source = (tomlFormat.generate "alacritty.toml" cfg.settings).overrideAttrs
|
source = (tomlFormat.generate "alacritty.toml" cfg.settings).overrideAttrs (
|
||||||
(finalAttrs: prevAttrs: {
|
finalAttrs: prevAttrs: {
|
||||||
buildCommand = lib.concatStringsSep "\n" [
|
buildCommand = lib.concatStringsSep "\n" [
|
||||||
prevAttrs.buildCommand
|
prevAttrs.buildCommand
|
||||||
# TODO: why is this needed? Is there a better way to retain escape sequences?
|
# TODO: why is this needed? Is there a better way to retain escape sequences?
|
||||||
"substituteInPlace $out --replace-quiet '\\\\' '\\'"
|
"substituteInPlace $out --replace-quiet '\\\\' '\\'"
|
||||||
];
|
];
|
||||||
});
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
pkgs:
|
pkgs:
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
let inherit (lib) mkOption types;
|
let
|
||||||
in {
|
inherit (lib) mkOption types;
|
||||||
|
in
|
||||||
|
{
|
||||||
options.alot = {
|
options.alot = {
|
||||||
sendMailCommand = mkOption {
|
sendMailCommand = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
|
|
@ -16,11 +18,9 @@ in {
|
||||||
type = types.attrsOf types.str;
|
type = types.attrsOf types.str;
|
||||||
default = {
|
default = {
|
||||||
type = "shellcommand";
|
type = "shellcommand";
|
||||||
command =
|
command = "'${pkgs.notmuch}/bin/notmuch address --format=json --output=recipients date:6M..'";
|
||||||
"'${pkgs.notmuch}/bin/notmuch address --format=json --output=recipients date:6M..'";
|
regexp =
|
||||||
regexp = "'\\[?{" + ''
|
"'\\[?{" + ''"name": "(?P<name>.*)", "address": "(?P<email>.+)", "name-addr": ".*"'' + "}[,\\]]?'";
|
||||||
"name": "(?P<name>.*)", "address": "(?P<email>.+)", "name-addr": ".*"''
|
|
||||||
+ "}[,\\]]?'";
|
|
||||||
shellcommand_external_filtering = "False";
|
shellcommand_external_filtering = "False";
|
||||||
};
|
};
|
||||||
example = lib.literalExpression ''
|
example = lib.literalExpression ''
|
||||||
|
|
@ -48,9 +48,8 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf config.notmuch.enable {
|
config = lib.mkIf config.notmuch.enable {
|
||||||
alot.sendMailCommand = lib.mkOptionDefault (if config.msmtp.enable then
|
alot.sendMailCommand = lib.mkOptionDefault (
|
||||||
"msmtpq --read-envelope-from --read-recipients"
|
if config.msmtp.enable then "msmtpq --read-envelope-from --read-recipients" else null
|
||||||
else
|
);
|
||||||
null);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,35 @@
|
||||||
# alot config loader is sensitive to leading space !
|
# alot config loader is sensitive to leading space !
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
concatStringsSep mapAttrsToList mkOption optionalAttrs optionalString types;
|
concatStringsSep
|
||||||
|
mapAttrsToList
|
||||||
|
mkOption
|
||||||
|
optionalAttrs
|
||||||
|
optionalString
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.programs.alot;
|
cfg = config.programs.alot;
|
||||||
|
|
||||||
enabledAccounts = lib.filter (a: a.notmuch.enable)
|
enabledAccounts = lib.filter (a: a.notmuch.enable) (lib.attrValues config.accounts.email.accounts);
|
||||||
(lib.attrValues config.accounts.email.accounts);
|
|
||||||
|
|
||||||
# sorted: primary first
|
# sorted: primary first
|
||||||
alotAccounts = lib.sort (a: b: !(a.primary -> b.primary)) enabledAccounts;
|
alotAccounts = lib.sort (a: b: !(a.primary -> b.primary)) enabledAccounts;
|
||||||
|
|
||||||
boolStr = v: if v then "True" else "False";
|
boolStr = v: if v then "True" else "False";
|
||||||
|
|
||||||
mkKeyValue = key: value:
|
mkKeyValue =
|
||||||
let value' = if lib.isBool value then boolStr value else toString value;
|
key: value:
|
||||||
in "${key} = ${value'}";
|
let
|
||||||
|
value' = if lib.isBool value then boolStr value else toString value;
|
||||||
|
in
|
||||||
|
"${key} = ${value'}";
|
||||||
|
|
||||||
mk2ndLevelSectionName = name: "[" + name + "]";
|
mk2ndLevelSectionName = name: "[" + name + "]";
|
||||||
|
|
||||||
|
|
@ -59,67 +72,95 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
accountStr = account:
|
accountStr =
|
||||||
|
account:
|
||||||
let
|
let
|
||||||
inherit (account)
|
inherit (account)
|
||||||
alot maildir name address realName folders aliases gpg signature;
|
alot
|
||||||
in concatStringsSep "\n" ([ "[[${name}]]" ]
|
maildir
|
||||||
++ mapAttrsToList (n: v: n + "=" + v) ({
|
name
|
||||||
address = address;
|
address
|
||||||
realname = realName;
|
realName
|
||||||
sendmail_command =
|
folders
|
||||||
optionalString (alot.sendMailCommand != null) alot.sendMailCommand;
|
aliases
|
||||||
} // optionalAttrs (folders.sent != null) {
|
gpg
|
||||||
sent_box = "maildir" + "://" + maildir.absPath + "/" + folders.sent;
|
signature
|
||||||
} // optionalAttrs (folders.drafts != null) {
|
;
|
||||||
draft_box = "maildir" + "://" + maildir.absPath + "/" + folders.drafts;
|
in
|
||||||
} // optionalAttrs (aliases != [ ]) {
|
concatStringsSep "\n" (
|
||||||
aliases = concatStringsSep "," aliases;
|
[ "[[${name}]]" ]
|
||||||
} // optionalAttrs (gpg != null) {
|
++ mapAttrsToList (n: v: n + "=" + v) (
|
||||||
gpg_key = gpg.key;
|
{
|
||||||
encrypt_by_default = if gpg.encryptByDefault then "all" else "none";
|
address = address;
|
||||||
sign_by_default = boolStr gpg.signByDefault;
|
realname = realName;
|
||||||
} // optionalAttrs (signature.showSignature != "none") {
|
sendmail_command = optionalString (alot.sendMailCommand != null) alot.sendMailCommand;
|
||||||
signature = pkgs.writeText "signature.txt" signature.text;
|
}
|
||||||
signature_as_attachment = boolStr (signature.showSignature == "attach");
|
// optionalAttrs (folders.sent != null) {
|
||||||
}) ++ [ alot.extraConfig ] ++ [ "[[[abook]]]" ]
|
sent_box = "maildir" + "://" + maildir.absPath + "/" + folders.sent;
|
||||||
++ mapAttrsToList (n: v: n + "=" + v) alot.contactCompletion);
|
}
|
||||||
|
// optionalAttrs (folders.drafts != null) {
|
||||||
|
draft_box = "maildir" + "://" + maildir.absPath + "/" + folders.drafts;
|
||||||
|
}
|
||||||
|
// optionalAttrs (aliases != [ ]) {
|
||||||
|
aliases = concatStringsSep "," aliases;
|
||||||
|
}
|
||||||
|
// 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") {
|
||||||
|
signature = pkgs.writeText "signature.txt" signature.text;
|
||||||
|
signature_as_attachment = boolStr (signature.showSignature == "attach");
|
||||||
|
}
|
||||||
|
)
|
||||||
|
++ [ alot.extraConfig ]
|
||||||
|
++ [ "[[[abook]]]" ]
|
||||||
|
++ mapAttrsToList (n: v: n + "=" + v) alot.contactCompletion
|
||||||
|
);
|
||||||
|
|
||||||
configFile = let
|
configFile =
|
||||||
bindingsToStr = attrSet:
|
let
|
||||||
concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${v}") attrSet);
|
bindingsToStr = attrSet: concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${v}") attrSet);
|
||||||
in ''
|
in
|
||||||
# Generated by Home Manager.
|
''
|
||||||
# See http://alot.readthedocs.io/en/latest/configuration/config_options.html
|
# Generated by Home Manager.
|
||||||
|
# See http://alot.readthedocs.io/en/latest/configuration/config_options.html
|
||||||
|
|
||||||
${lib.generators.toKeyValue { inherit mkKeyValue; } cfg.settings}
|
${lib.generators.toKeyValue { inherit mkKeyValue; } cfg.settings}
|
||||||
${cfg.extraConfig}
|
${cfg.extraConfig}
|
||||||
[tags]
|
[tags]
|
||||||
'' + (let
|
''
|
||||||
submoduleToAttrs = m:
|
+ (
|
||||||
lib.filterAttrs (name: v: name != "_module" && v != null) m;
|
let
|
||||||
in lib.generators.toINI { mkSectionName = mk2ndLevelSectionName; }
|
submoduleToAttrs = m: lib.filterAttrs (name: v: name != "_module" && v != null) m;
|
||||||
(lib.mapAttrs (name: x: submoduleToAttrs x) cfg.tags)) + ''
|
in
|
||||||
[bindings]
|
lib.generators.toINI { mkSectionName = mk2ndLevelSectionName; } (
|
||||||
${bindingsToStr cfg.bindings.global}
|
lib.mapAttrs (name: x: submoduleToAttrs x) cfg.tags
|
||||||
|
)
|
||||||
|
)
|
||||||
|
+ ''
|
||||||
|
[bindings]
|
||||||
|
${bindingsToStr cfg.bindings.global}
|
||||||
|
|
||||||
[[bufferlist]]
|
[[bufferlist]]
|
||||||
${bindingsToStr cfg.bindings.bufferlist}
|
${bindingsToStr cfg.bindings.bufferlist}
|
||||||
[[search]]
|
[[search]]
|
||||||
${bindingsToStr cfg.bindings.search}
|
${bindingsToStr cfg.bindings.search}
|
||||||
[[envelope]]
|
[[envelope]]
|
||||||
${bindingsToStr cfg.bindings.envelope}
|
${bindingsToStr cfg.bindings.envelope}
|
||||||
[[taglist]]
|
[[taglist]]
|
||||||
${bindingsToStr cfg.bindings.taglist}
|
${bindingsToStr cfg.bindings.taglist}
|
||||||
[[thread]]
|
[[thread]]
|
||||||
${bindingsToStr cfg.bindings.thread}
|
${bindingsToStr cfg.bindings.thread}
|
||||||
|
|
||||||
[accounts]
|
[accounts]
|
||||||
|
|
||||||
${lib.concatStringsSep "\n\n" (map accountStr alotAccounts)}
|
${lib.concatStringsSep "\n\n" (map accountStr alotAccounts)}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
programs.alot = {
|
programs.alot = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
|
|
@ -196,9 +237,12 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
settings = mkOption {
|
settings = mkOption {
|
||||||
type = with types;
|
type =
|
||||||
let primitive = either (either (either str int) bool) float;
|
with types;
|
||||||
in attrsOf primitive;
|
let
|
||||||
|
primitive = either (either (either str int) bool) float;
|
||||||
|
in
|
||||||
|
attrsOf primitive;
|
||||||
default = {
|
default = {
|
||||||
initial_command = "search tag:inbox AND NOT tag:killed";
|
initial_command = "search tag:inbox AND NOT tag:killed";
|
||||||
auto_remove_unread = true;
|
auto_remove_unread = true;
|
||||||
|
|
@ -237,9 +281,11 @@ in {
|
||||||
xdg.configFile."alot/config".text = configFile;
|
xdg.configFile."alot/config".text = configFile;
|
||||||
|
|
||||||
xdg.configFile."alot/hooks.py" = lib.mkIf (cfg.hooks != "") {
|
xdg.configFile."alot/hooks.py" = lib.mkIf (cfg.hooks != "") {
|
||||||
text = ''
|
text =
|
||||||
# Generated by Home Manager.
|
''
|
||||||
'' + cfg.hooks;
|
# Generated by Home Manager.
|
||||||
|
''
|
||||||
|
+ cfg.hooks;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,25 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
cfg = config.programs.zsh.antidote;
|
cfg = config.programs.zsh.antidote;
|
||||||
|
|
||||||
zPluginStr = (pluginNames:
|
zPluginStr = (
|
||||||
lib.optionalString (pluginNames != [ ]) "${lib.concatStrings (map (name: ''
|
pluginNames:
|
||||||
${name}
|
lib.optionalString (pluginNames != [ ])
|
||||||
'') pluginNames)}");
|
"${lib.concatStrings (
|
||||||
|
map (name: ''
|
||||||
|
${name}
|
||||||
|
'') pluginNames
|
||||||
|
)}"
|
||||||
|
);
|
||||||
|
|
||||||
parseHashId = path:
|
parseHashId = path: lib.elemAt (builtins.match "${builtins.storeDir}/([a-zA-Z0-9]+)-.*" path) 0;
|
||||||
lib.elemAt (builtins.match "${builtins.storeDir}/([a-zA-Z0-9]+)-.*" path) 0;
|
in
|
||||||
in {
|
{
|
||||||
meta.maintainers = [ lib.maintainers.hitsmaxft ];
|
meta.maintainers = [ lib.maintainers.hitsmaxft ];
|
||||||
|
|
||||||
options.programs.zsh.antidote = {
|
options.programs.zsh.antidote = {
|
||||||
|
|
@ -30,25 +40,26 @@ in {
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
|
|
||||||
programs.zsh.initContent = let
|
programs.zsh.initContent =
|
||||||
configFiles = pkgs.runCommand "hm_antidote-files" { } ''
|
let
|
||||||
echo "${zPluginStr cfg.plugins}" > $out
|
configFiles = pkgs.runCommand "hm_antidote-files" { } ''
|
||||||
'';
|
echo "${zPluginStr cfg.plugins}" > $out
|
||||||
hashId = parseHashId "${configFiles}";
|
'';
|
||||||
in (lib.mkOrder 550 ''
|
hashId = parseHashId "${configFiles}";
|
||||||
## home-manager/antidote begin :
|
in
|
||||||
source ${cfg.package}/share/antidote/antidote.zsh
|
(lib.mkOrder 550 ''
|
||||||
${lib.optionalString cfg.useFriendlyNames
|
## home-manager/antidote begin :
|
||||||
"zstyle ':antidote:bundle' use-friendly-names 'yes'"}
|
source ${cfg.package}/share/antidote/antidote.zsh
|
||||||
|
${lib.optionalString cfg.useFriendlyNames "zstyle ':antidote:bundle' use-friendly-names 'yes'"}
|
||||||
|
|
||||||
bundlefile=${configFiles}
|
bundlefile=${configFiles}
|
||||||
zstyle ':antidote:bundle' file $bundlefile
|
zstyle ':antidote:bundle' file $bundlefile
|
||||||
staticfile=/tmp/tmp_hm_zsh_plugins.zsh-${hashId}
|
staticfile=/tmp/tmp_hm_zsh_plugins.zsh-${hashId}
|
||||||
zstyle ':antidote:static' file $staticfile
|
zstyle ':antidote:static' file $staticfile
|
||||||
|
|
||||||
antidote load $bundlefile $staticfile
|
antidote load $bundlefile $staticfile
|
||||||
|
|
||||||
## home-manager/antidote end
|
## home-manager/antidote end
|
||||||
'');
|
'');
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,20 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
cfg = config.programs.aria2;
|
cfg = config.programs.aria2;
|
||||||
|
|
||||||
formatLine = n: v:
|
formatLine =
|
||||||
|
n: v:
|
||||||
let
|
let
|
||||||
formatValue = v:
|
formatValue = v: if builtins.isBool v then (if v then "true" else "false") else toString v;
|
||||||
if builtins.isBool v then
|
in
|
||||||
(if v then "true" else "false")
|
"${n}=${formatValue v}";
|
||||||
else
|
in
|
||||||
toString v;
|
{
|
||||||
in "${n}=${formatValue v}";
|
|
||||||
in {
|
|
||||||
meta.maintainers = [ lib.hm.maintainers.justinlovinger ];
|
meta.maintainers = [ lib.hm.maintainers.justinlovinger ];
|
||||||
|
|
||||||
options.programs.aria2 = {
|
options.programs.aria2 = {
|
||||||
|
|
@ -19,7 +23,14 @@ in {
|
||||||
package = lib.mkPackageOption pkgs "aria2" { nullable = true; };
|
package = lib.mkPackageOption pkgs "aria2" { nullable = true; };
|
||||||
|
|
||||||
settings = lib.mkOption {
|
settings = lib.mkOption {
|
||||||
type = with lib.types; attrsOf (oneOf [ bool float int str ]);
|
type =
|
||||||
|
with lib.types;
|
||||||
|
attrsOf (oneOf [
|
||||||
|
bool
|
||||||
|
float
|
||||||
|
int
|
||||||
|
str
|
||||||
|
]);
|
||||||
default = { };
|
default = { };
|
||||||
description = ''
|
description = ''
|
||||||
Options to add to {file}`aria2.conf` file.
|
Options to add to {file}`aria2.conf` file.
|
||||||
|
|
@ -50,8 +61,10 @@ in {
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
|
|
||||||
xdg.configFile."aria2/aria2.conf".text = lib.concatStringsSep "\n" ([ ]
|
xdg.configFile."aria2/aria2.conf".text = lib.concatStringsSep "\n" (
|
||||||
|
[ ]
|
||||||
++ lib.mapAttrsToList formatLine cfg.settings
|
++ lib.mapAttrsToList formatLine cfg.settings
|
||||||
++ lib.optional (cfg.extraConfig != "") cfg.extraConfig);
|
++ lib.optional (cfg.extraConfig != "") cfg.extraConfig
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
{ config, lib, ... }: {
|
{ config, lib, ... }:
|
||||||
|
{
|
||||||
options.astroid = {
|
options.astroid = {
|
||||||
enable = lib.mkEnableOption "Astroid";
|
enable = lib.mkEnableOption "Astroid";
|
||||||
|
|
||||||
|
|
@ -14,7 +15,9 @@
|
||||||
extraConfig = lib.mkOption {
|
extraConfig = lib.mkOption {
|
||||||
type = lib.types.attrsOf lib.types.anything;
|
type = lib.types.attrsOf lib.types.anything;
|
||||||
default = { };
|
default = { };
|
||||||
example = { select_query = ""; };
|
example = {
|
||||||
|
select_query = "";
|
||||||
|
};
|
||||||
description = ''
|
description = ''
|
||||||
Extra settings to add to this astroid account configuration.
|
Extra settings to add to this astroid account configuration.
|
||||||
'';
|
'';
|
||||||
|
|
@ -22,7 +25,8 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf config.notmuch.enable {
|
config = lib.mkIf config.notmuch.enable {
|
||||||
astroid.sendMailCommand = lib.mkIf config.msmtp.enable
|
astroid.sendMailCommand = lib.mkIf config.msmtp.enable (
|
||||||
(lib.mkOptionDefault "msmtpq --read-envelope-from --read-recipients");
|
lib.mkOptionDefault "msmtpq --read-envelope-from --read-recipients"
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types;
|
||||||
|
|
||||||
|
|
@ -6,12 +11,12 @@ let
|
||||||
|
|
||||||
jsonFormat = pkgs.formats.json { };
|
jsonFormat = pkgs.formats.json { };
|
||||||
|
|
||||||
astroidAccounts =
|
astroidAccounts = lib.filterAttrs (n: v: v.astroid.enable) config.accounts.email.accounts;
|
||||||
lib.filterAttrs (n: v: v.astroid.enable) config.accounts.email.accounts;
|
|
||||||
|
|
||||||
boolOpt = b: if b then "true" else "false";
|
boolOpt = b: if b then "true" else "false";
|
||||||
|
|
||||||
accountAttr = account:
|
accountAttr =
|
||||||
|
account:
|
||||||
with account;
|
with account;
|
||||||
{
|
{
|
||||||
email = address;
|
email = address;
|
||||||
|
|
@ -23,33 +28,38 @@ let
|
||||||
save_sent = "true";
|
save_sent = "true";
|
||||||
save_sent_to = "${maildir.absPath}/${folders.sent}/cur/";
|
save_sent_to = "${maildir.absPath}/${folders.sent}/cur/";
|
||||||
select_query = "";
|
select_query = "";
|
||||||
} // lib.optionalAttrs (signature.showSignature != "none") {
|
}
|
||||||
|
// lib.optionalAttrs (signature.showSignature != "none") {
|
||||||
signature_attach = boolOpt (signature.showSignature == "attach");
|
signature_attach = boolOpt (signature.showSignature == "attach");
|
||||||
signature_default_on = boolOpt (signature.showSignature != "none");
|
signature_default_on = boolOpt (signature.showSignature != "none");
|
||||||
signature_file = pkgs.writeText "signature.txt" signature.text;
|
signature_file = pkgs.writeText "signature.txt" signature.text;
|
||||||
signature_file_markdown = "false";
|
signature_file_markdown = "false";
|
||||||
signature_separate = "true"; # prepends '--\n' to the signature
|
signature_separate = "true"; # prepends '--\n' to the signature
|
||||||
} // lib.optionalAttrs (gpg != null) {
|
}
|
||||||
|
// lib.optionalAttrs (gpg != null) {
|
||||||
always_gpg_sign = boolOpt gpg.signByDefault;
|
always_gpg_sign = boolOpt gpg.signByDefault;
|
||||||
gpgkey = gpg.key;
|
gpgkey = gpg.key;
|
||||||
} // astroid.extraConfig;
|
}
|
||||||
|
// astroid.extraConfig;
|
||||||
|
|
||||||
# See https://github.com/astroidmail/astroid/wiki/Configuration-Reference
|
# See https://github.com/astroidmail/astroid/wiki/Configuration-Reference
|
||||||
finalConfig = let
|
finalConfig =
|
||||||
template = lib.importJSON ./astroid-config-template.json;
|
let
|
||||||
astroidConfig = lib.foldl' lib.recursiveUpdate template [
|
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;
|
accounts = lib.mapAttrs (n: accountAttr) astroidAccounts;
|
||||||
crypto.gpg.path = "${pkgs.gnupg}/bin/gpg";
|
crypto.gpg.path = "${pkgs.gnupg}/bin/gpg";
|
||||||
}
|
}
|
||||||
cfg.extraConfig
|
cfg.extraConfig
|
||||||
cfg.externalEditor
|
cfg.externalEditor
|
||||||
];
|
];
|
||||||
in astroidConfig;
|
in
|
||||||
|
astroidConfig;
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
programs.astroid = {
|
programs.astroid = {
|
||||||
enable = lib.mkEnableOption "Astroid";
|
enable = lib.mkEnableOption "Astroid";
|
||||||
|
|
@ -69,15 +79,15 @@ in {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
# Converts it into JSON that can be merged into the configuration.
|
# Converts it into JSON that can be merged into the configuration.
|
||||||
apply = cmd:
|
apply =
|
||||||
|
cmd:
|
||||||
lib.optionalAttrs (cmd != null) {
|
lib.optionalAttrs (cmd != null) {
|
||||||
editor = {
|
editor = {
|
||||||
"external_editor" = "true";
|
"external_editor" = "true";
|
||||||
"cmd" = cmd;
|
"cmd" = cmd;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
example =
|
example = "nvim-qt -- -c 'set ft=mail' '+set fileencoding=utf-8' '+set ff=unix' '+set enc=utf-8' '+set fo+=w' %1";
|
||||||
"nvim-qt -- -c 'set ft=mail' '+set fileencoding=utf-8' '+set ff=unix' '+set enc=utf-8' '+set fo+=w' %1";
|
|
||||||
description = ''
|
description = ''
|
||||||
You can use the following variables:
|
You can use the following variables:
|
||||||
|
|
||||||
|
|
@ -117,8 +127,7 @@ in {
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
|
|
||||||
xdg.configFile."astroid/config".source =
|
xdg.configFile."astroid/config".source = jsonFormat.generate "astroid-config" finalConfig;
|
||||||
jsonFormat.generate "astroid-config" finalConfig;
|
|
||||||
|
|
||||||
xdg.configFile."astroid/poll.sh" = lib.mkIf (cfg.pollScript != "") {
|
xdg.configFile."astroid/poll.sh" = lib.mkIf (cfg.pollScript != "") {
|
||||||
executable = true;
|
executable = true;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
cfg = config.programs.atuin;
|
cfg = config.programs.atuin;
|
||||||
daemonCfg = cfg.daemon;
|
daemonCfg = cfg.daemon;
|
||||||
|
|
@ -7,8 +12,12 @@ let
|
||||||
|
|
||||||
inherit (lib) mkIf mkOption types;
|
inherit (lib) mkIf mkOption types;
|
||||||
inherit (pkgs.stdenv) isLinux isDarwin;
|
inherit (pkgs.stdenv) isLinux isDarwin;
|
||||||
in {
|
in
|
||||||
meta.maintainers = with lib.maintainers; [ hawkw water-sucks ];
|
{
|
||||||
|
meta.maintainers = with lib.maintainers; [
|
||||||
|
hawkw
|
||||||
|
water-sucks
|
||||||
|
];
|
||||||
|
|
||||||
options.programs.atuin = {
|
options.programs.atuin = {
|
||||||
enable = lib.mkEnableOption "atuin";
|
enable = lib.mkEnableOption "atuin";
|
||||||
|
|
@ -17,18 +26,15 @@ in {
|
||||||
|
|
||||||
enableBashIntegration = lib.hm.shell.mkBashIntegrationOption {
|
enableBashIntegration = lib.hm.shell.mkBashIntegrationOption {
|
||||||
inherit config;
|
inherit config;
|
||||||
extraDescription =
|
extraDescription = "If enabled, this will bind `ctrl-r` to open the Atuin history.";
|
||||||
"If enabled, this will bind `ctrl-r` to open the Atuin history.";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enableFishIntegration = lib.hm.shell.mkFishIntegrationOption {
|
enableFishIntegration = lib.hm.shell.mkFishIntegrationOption {
|
||||||
inherit config;
|
inherit config;
|
||||||
extraDescription =
|
extraDescription = "If enabled, this will bind the up-arrow key to open the Atuin history.";
|
||||||
"If enabled, this will bind the up-arrow key to open the Atuin history.";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enableNushellIntegration =
|
enableNushellIntegration = lib.hm.shell.mkNushellIntegrationOption { inherit config; };
|
||||||
lib.hm.shell.mkNushellIntegrationOption { inherit config; };
|
|
||||||
|
|
||||||
enableZshIntegration = lib.hm.shell.mkZshIntegrationOption {
|
enableZshIntegration = lib.hm.shell.mkZshIntegrationOption {
|
||||||
inherit config;
|
inherit config;
|
||||||
|
|
@ -41,21 +47,30 @@ in {
|
||||||
flags = mkOption {
|
flags = mkOption {
|
||||||
default = [ ];
|
default = [ ];
|
||||||
type = types.listOf types.str;
|
type = types.listOf types.str;
|
||||||
example = [ "--disable-up-arrow" "--disable-ctrl-r" ];
|
example = [
|
||||||
|
"--disable-up-arrow"
|
||||||
|
"--disable-ctrl-r"
|
||||||
|
];
|
||||||
description = ''
|
description = ''
|
||||||
Flags to append to the shell hook.
|
Flags to append to the shell hook.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
settings = mkOption {
|
settings = mkOption {
|
||||||
type = with types;
|
type =
|
||||||
|
with types;
|
||||||
let
|
let
|
||||||
prim = oneOf [ bool int str ];
|
prim = oneOf [
|
||||||
|
bool
|
||||||
|
int
|
||||||
|
str
|
||||||
|
];
|
||||||
primOrPrimAttrs = either prim (attrsOf prim);
|
primOrPrimAttrs = either prim (attrsOf prim);
|
||||||
entry = either prim (listOf primOrPrimAttrs);
|
entry = either prim (listOf primOrPrimAttrs);
|
||||||
entryOrAttrsOf = t: either entry (attrsOf t);
|
entryOrAttrsOf = t: either entry (attrsOf t);
|
||||||
entries = entryOrAttrsOf (entryOrAttrsOf entry);
|
entries = entryOrAttrsOf (entryOrAttrsOf entry);
|
||||||
in attrsOf entries // { description = "Atuin configuration"; };
|
in
|
||||||
|
attrsOf entries // { description = "Atuin configuration"; };
|
||||||
default = { };
|
default = { };
|
||||||
example = lib.literalExpression ''
|
example = lib.literalExpression ''
|
||||||
{
|
{
|
||||||
|
|
@ -79,8 +94,15 @@ in {
|
||||||
|
|
||||||
logLevel = mkOption {
|
logLevel = mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
type =
|
type = types.nullOr (
|
||||||
types.nullOr (types.enum [ "trace" "debug" "info" "warn" "error" ]);
|
types.enum [
|
||||||
|
"trace"
|
||||||
|
"debug"
|
||||||
|
"info"
|
||||||
|
"warn"
|
||||||
|
"error"
|
||||||
|
]
|
||||||
|
);
|
||||||
description = ''
|
description = ''
|
||||||
Verbosity of Atuin daemon logging.
|
Verbosity of Atuin daemon logging.
|
||||||
'';
|
'';
|
||||||
|
|
@ -88,126 +110,145 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let flagsStr = lib.escapeShellArgs cfg.flags;
|
config =
|
||||||
in mkIf cfg.enable (lib.mkMerge [
|
let
|
||||||
{
|
flagsStr = lib.escapeShellArgs cfg.flags;
|
||||||
# Always add the configured `atuin` package.
|
in
|
||||||
home.packages = [ cfg.package ];
|
mkIf cfg.enable (
|
||||||
|
lib.mkMerge [
|
||||||
|
{
|
||||||
|
# Always add the configured `atuin` package.
|
||||||
|
home.packages = [ cfg.package ];
|
||||||
|
|
||||||
# If there are user-provided settings, generate the config file.
|
# If there are user-provided settings, generate the config file.
|
||||||
xdg.configFile."atuin/config.toml" = mkIf (cfg.settings != { }) {
|
xdg.configFile."atuin/config.toml" = mkIf (cfg.settings != { }) {
|
||||||
source = tomlFormat.generate "atuin-config" cfg.settings;
|
source = tomlFormat.generate "atuin-config" cfg.settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.bash.initExtra = mkIf cfg.enableBashIntegration ''
|
programs.bash.initExtra = mkIf cfg.enableBashIntegration ''
|
||||||
if [[ :$SHELLOPTS: =~ :(vi|emacs): ]]; then
|
if [[ :$SHELLOPTS: =~ :(vi|emacs): ]]; then
|
||||||
source "${pkgs.bash-preexec}/share/bash/bash-preexec.sh"
|
source "${pkgs.bash-preexec}/share/bash/bash-preexec.sh"
|
||||||
eval "$(${lib.getExe cfg.package} init bash ${flagsStr})"
|
eval "$(${lib.getExe cfg.package} init bash ${flagsStr})"
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
programs.zsh.initContent = mkIf cfg.enableZshIntegration ''
|
programs.zsh.initContent = mkIf cfg.enableZshIntegration ''
|
||||||
if [[ $options[zle] = on ]]; then
|
if [[ $options[zle] = on ]]; then
|
||||||
eval "$(${lib.getExe cfg.package} init zsh ${flagsStr})"
|
eval "$(${lib.getExe cfg.package} init zsh ${flagsStr})"
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration ''
|
programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration ''
|
||||||
${lib.getExe cfg.package} init fish ${flagsStr} | source
|
${lib.getExe cfg.package} init fish ${flagsStr} | source
|
||||||
'';
|
'';
|
||||||
|
|
||||||
programs.nushell = mkIf cfg.enableNushellIntegration {
|
programs.nushell = mkIf cfg.enableNushellIntegration {
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
source ${
|
source ${
|
||||||
pkgs.runCommand "atuin-nushell-config.nu" {
|
pkgs.runCommand "atuin-nushell-config.nu"
|
||||||
nativeBuildInputs = [ pkgs.writableTmpDirAsHomeHook ];
|
{
|
||||||
} ''
|
nativeBuildInputs = [ pkgs.writableTmpDirAsHomeHook ];
|
||||||
${lib.getExe cfg.package} init nu ${flagsStr} >> "$out"
|
}
|
||||||
''
|
''
|
||||||
}
|
${lib.getExe cfg.package} init nu ${flagsStr} >> "$out"
|
||||||
'';
|
''
|
||||||
};
|
}
|
||||||
}
|
|
||||||
|
|
||||||
(mkIf daemonCfg.enable (lib.mkMerge [
|
|
||||||
{
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = lib.versionAtLeast cfg.package.version "18.2.0";
|
|
||||||
message = ''
|
|
||||||
The Atuin daemon requires at least version 18.2.0 or later.
|
|
||||||
'';
|
'';
|
||||||
}
|
};
|
||||||
{
|
}
|
||||||
assertion = isLinux || isDarwin;
|
|
||||||
message =
|
|
||||||
"The Atuin daemon can only be configured on either Linux or macOS.";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
programs.atuin.settings = { daemon = { enabled = true; }; };
|
(mkIf daemonCfg.enable (
|
||||||
}
|
lib.mkMerge [
|
||||||
(mkIf isLinux {
|
{
|
||||||
programs.atuin.settings = { daemon = { systemd_socket = true; }; };
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = lib.versionAtLeast cfg.package.version "18.2.0";
|
||||||
|
message = ''
|
||||||
|
The Atuin daemon requires at least version 18.2.0 or later.
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = isLinux || isDarwin;
|
||||||
|
message = "The Atuin daemon can only be configured on either Linux or macOS.";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
systemd.user.services.atuin-daemon = {
|
programs.atuin.settings = {
|
||||||
Unit = {
|
daemon = {
|
||||||
Description = "Atuin daemon";
|
enabled = true;
|
||||||
Requires = [ "atuin-daemon.socket" ];
|
};
|
||||||
};
|
|
||||||
Install = {
|
|
||||||
Also = [ "atuin-daemon.socket" ];
|
|
||||||
WantedBy = [ "default.target" ];
|
|
||||||
};
|
|
||||||
Service = {
|
|
||||||
ExecStart = "${lib.getExe cfg.package} daemon";
|
|
||||||
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" ]; };
|
|
||||||
Socket = {
|
|
||||||
ListenStream = "${socket_dir}/atuin.sock";
|
|
||||||
SocketMode = "0600";
|
|
||||||
RemoveOnStop = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
(mkIf isDarwin {
|
|
||||||
programs.atuin.settings = {
|
|
||||||
daemon = {
|
|
||||||
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) {
|
|
||||||
ATUIN_LOG = daemonCfg.logLevel;
|
|
||||||
};
|
};
|
||||||
KeepAlive = {
|
}
|
||||||
Crashed = true;
|
(mkIf isLinux {
|
||||||
SuccessfulExit = false;
|
programs.atuin.settings = {
|
||||||
};
|
daemon = {
|
||||||
ProcessType = "Background";
|
systemd_socket = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
})
|
|
||||||
]))
|
systemd.user.services.atuin-daemon = {
|
||||||
]);
|
Unit = {
|
||||||
|
Description = "Atuin daemon";
|
||||||
|
Requires = [ "atuin-daemon.socket" ];
|
||||||
|
};
|
||||||
|
Install = {
|
||||||
|
Also = [ "atuin-daemon.socket" ];
|
||||||
|
WantedBy = [ "default.target" ];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
ExecStart = "${lib.getExe cfg.package} daemon";
|
||||||
|
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" ];
|
||||||
|
};
|
||||||
|
Socket = {
|
||||||
|
ListenStream = "${socket_dir}/atuin.sock";
|
||||||
|
SocketMode = "0600";
|
||||||
|
RemoveOnStop = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
(mkIf isDarwin {
|
||||||
|
programs.atuin.settings = {
|
||||||
|
daemon = {
|
||||||
|
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) {
|
||||||
|
ATUIN_LOG = daemonCfg.logLevel;
|
||||||
|
};
|
||||||
|
KeepAlive = {
|
||||||
|
Crashed = true;
|
||||||
|
SuccessfulExit = false;
|
||||||
|
};
|
||||||
|
ProcessType = "Background";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]
|
||||||
|
))
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
cfg = config.programs.autojump;
|
cfg = config.programs.autojump;
|
||||||
|
|
||||||
inherit (lib) mkIf;
|
inherit (lib) mkIf;
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.evanjs ];
|
meta.maintainers = [ lib.maintainers.evanjs ];
|
||||||
|
|
||||||
options.programs.autojump = {
|
options.programs.autojump = {
|
||||||
|
|
@ -11,22 +17,21 @@ in {
|
||||||
|
|
||||||
package = lib.mkPackageOption pkgs "autojump" { };
|
package = lib.mkPackageOption pkgs "autojump" { };
|
||||||
|
|
||||||
enableBashIntegration =
|
enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { inherit config; };
|
||||||
lib.hm.shell.mkBashIntegrationOption { inherit config; };
|
|
||||||
|
|
||||||
enableFishIntegration =
|
enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { inherit config; };
|
||||||
lib.hm.shell.mkFishIntegrationOption { inherit config; };
|
|
||||||
|
|
||||||
enableZshIntegration =
|
enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; };
|
||||||
lib.hm.shell.mkZshIntegrationOption { inherit config; };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
home.packages = [ cfg.package ];
|
home.packages = [ cfg.package ];
|
||||||
|
|
||||||
programs.bash.initExtra = mkIf cfg.enableBashIntegration (lib.mkBefore ''
|
programs.bash.initExtra = mkIf cfg.enableBashIntegration (
|
||||||
. ${cfg.package}/share/autojump/autojump.bash
|
lib.mkBefore ''
|
||||||
'');
|
. ${cfg.package}/share/autojump/autojump.bash
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
programs.zsh.initContent = mkIf cfg.enableZshIntegration ''
|
programs.zsh.initContent = mkIf cfg.enableZshIntegration ''
|
||||||
. ${cfg.package}/share/autojump/autojump.zsh
|
. ${cfg.package}/share/autojump/autojump.zsh
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,49 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
literalExpression listToAttrs mapAttrs' mapAttrsToList mkIf mkOption
|
literalExpression
|
||||||
optional types;
|
listToAttrs
|
||||||
|
mapAttrs'
|
||||||
|
mapAttrsToList
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
optional
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.programs.autorandr;
|
cfg = config.programs.autorandr;
|
||||||
|
|
||||||
matrixOf = n: m: elemType:
|
matrixOf =
|
||||||
|
n: m: elemType:
|
||||||
lib.mkOptionType rec {
|
lib.mkOptionType rec {
|
||||||
name = "matrixOf";
|
name = "matrixOf";
|
||||||
description =
|
description = "${toString n}×${toString m} matrix of ${elemType.description}s";
|
||||||
"${toString n}×${toString m} matrix of ${elemType.description}s";
|
check =
|
||||||
check = xss:
|
xss:
|
||||||
let listOfSize = l: xs: lib.isList xs && lib.length xs == l;
|
let
|
||||||
in listOfSize n xss
|
listOfSize = l: xs: lib.isList xs && lib.length xs == l;
|
||||||
&& lib.all (xs: listOfSize m xs && lib.all elemType.check xs) xss;
|
in
|
||||||
|
listOfSize n xss && lib.all (xs: listOfSize m xs && lib.all elemType.check xs) xss;
|
||||||
merge = lib.mergeOneOption;
|
merge = lib.mergeOneOption;
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "*" "*" ]);
|
getSubOptions =
|
||||||
|
prefix:
|
||||||
|
elemType.getSubOptions (
|
||||||
|
prefix
|
||||||
|
++ [
|
||||||
|
"*"
|
||||||
|
"*"
|
||||||
|
]
|
||||||
|
);
|
||||||
getSubModules = elemType.getSubModules;
|
getSubModules = elemType.getSubModules;
|
||||||
substSubModules = mod: matrixOf n m (elemType.substSubModules mod);
|
substSubModules = mod: matrixOf n m (elemType.substSubModules mod);
|
||||||
functor = (lib.defaultFunctor name) // { wrapped = elemType; };
|
functor = (lib.defaultFunctor name) // {
|
||||||
|
wrapped = elemType;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
profileModule = types.submodule {
|
profileModule = types.submodule {
|
||||||
|
|
@ -97,7 +121,14 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
rotate = mkOption {
|
rotate = mkOption {
|
||||||
type = types.nullOr (types.enum [ "normal" "left" "right" "inverted" ]);
|
type = types.nullOr (
|
||||||
|
types.enum [
|
||||||
|
"normal"
|
||||||
|
"left"
|
||||||
|
"right"
|
||||||
|
"inverted"
|
||||||
|
]
|
||||||
|
);
|
||||||
description = "Output rotate configuration.";
|
description = "Output rotate configuration.";
|
||||||
default = null;
|
default = null;
|
||||||
example = "left";
|
example = "left";
|
||||||
|
|
@ -128,26 +159,31 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
scale = mkOption {
|
scale = mkOption {
|
||||||
type = types.nullOr (types.submodule {
|
type = types.nullOr (
|
||||||
options = {
|
types.submodule {
|
||||||
method = mkOption {
|
options = {
|
||||||
type = types.enum [ "factor" "pixel" ];
|
method = mkOption {
|
||||||
description = "Output scaling method.";
|
type = types.enum [
|
||||||
default = "factor";
|
"factor"
|
||||||
example = "pixel";
|
"pixel"
|
||||||
};
|
];
|
||||||
|
description = "Output scaling method.";
|
||||||
|
default = "factor";
|
||||||
|
example = "pixel";
|
||||||
|
};
|
||||||
|
|
||||||
x = mkOption {
|
x = mkOption {
|
||||||
type = types.either types.float types.ints.positive;
|
type = types.either types.float types.ints.positive;
|
||||||
description = "Horizontal scaling factor/pixels.";
|
description = "Horizontal scaling factor/pixels.";
|
||||||
};
|
};
|
||||||
|
|
||||||
y = mkOption {
|
y = mkOption {
|
||||||
type = types.either types.float types.ints.positive;
|
type = types.either types.float types.ints.positive;
|
||||||
description = "Vertical scaling factor/pixels.";
|
description = "Vertical scaling factor/pixels.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
});
|
);
|
||||||
description = ''
|
description = ''
|
||||||
Output scale configuration.
|
Output scale configuration.
|
||||||
|
|
||||||
|
|
@ -172,7 +208,12 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
filter = mkOption {
|
filter = mkOption {
|
||||||
type = types.nullOr (types.enum [ "bilinear" "nearest" ]);
|
type = types.nullOr (
|
||||||
|
types.enum [
|
||||||
|
"bilinear"
|
||||||
|
"nearest"
|
||||||
|
]
|
||||||
|
);
|
||||||
description = "Interpolation method to be used for scaling the output.";
|
description = "Interpolation method to be used for scaling the output.";
|
||||||
default = null;
|
default = null;
|
||||||
example = "nearest";
|
example = "nearest";
|
||||||
|
|
@ -242,30 +283,35 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
hookToFile = folder: name: hook:
|
hookToFile =
|
||||||
|
folder: name: hook:
|
||||||
lib.nameValuePair "autorandr/${folder}/${name}" {
|
lib.nameValuePair "autorandr/${folder}/${name}" {
|
||||||
source = "${pkgs.writeShellScriptBin "hook" hook}/bin/hook";
|
source = "${pkgs.writeShellScriptBin "hook" hook}/bin/hook";
|
||||||
};
|
};
|
||||||
profileToFiles = name: profile:
|
profileToFiles =
|
||||||
let inherit (profile) hooks;
|
name: profile:
|
||||||
in lib.mkMerge [
|
let
|
||||||
|
inherit (profile) hooks;
|
||||||
|
in
|
||||||
|
lib.mkMerge [
|
||||||
{
|
{
|
||||||
"autorandr/${name}/setup".text = lib.concatStringsSep "\n"
|
"autorandr/${name}/setup".text = lib.concatStringsSep "\n" (
|
||||||
(mapAttrsToList fingerprintToString profile.fingerprint);
|
mapAttrsToList fingerprintToString profile.fingerprint
|
||||||
"autorandr/${name}/config".text = lib.concatStringsSep "\n"
|
);
|
||||||
(mapAttrsToList configToString profile.config);
|
"autorandr/${name}/config".text = lib.concatStringsSep "\n" (
|
||||||
|
mapAttrsToList configToString profile.config
|
||||||
|
);
|
||||||
}
|
}
|
||||||
(mkIf (hooks.postswitch != "")
|
(mkIf (hooks.postswitch != "") (listToAttrs [ (hookToFile name "postswitch" hooks.postswitch) ]))
|
||||||
(listToAttrs [ (hookToFile name "postswitch" hooks.postswitch) ]))
|
(mkIf (hooks.preswitch != "") (listToAttrs [ (hookToFile name "preswitch" hooks.preswitch) ]))
|
||||||
(mkIf (hooks.preswitch != "")
|
(mkIf (hooks.predetect != "") (listToAttrs [ (hookToFile name "predetect" hooks.predetect) ]))
|
||||||
(listToAttrs [ (hookToFile name "preswitch" hooks.preswitch) ]))
|
|
||||||
(mkIf (hooks.predetect != "")
|
|
||||||
(listToAttrs [ (hookToFile name "predetect" hooks.predetect) ]))
|
|
||||||
];
|
];
|
||||||
fingerprintToString = name: edid: "${name} ${edid}";
|
fingerprintToString = name: edid: "${name} ${edid}";
|
||||||
configToString = name: config:
|
configToString =
|
||||||
|
name: config:
|
||||||
if config.enable then
|
if config.enable then
|
||||||
lib.concatStringsSep "\n" ([ "output ${name}" ]
|
lib.concatStringsSep "\n" (
|
||||||
|
[ "output ${name}" ]
|
||||||
++ optional (config.position != "") "pos ${config.position}"
|
++ optional (config.position != "") "pos ${config.position}"
|
||||||
++ optional (config.crtc != null) "crtc ${toString config.crtc}"
|
++ optional (config.crtc != null) "crtc ${toString config.crtc}"
|
||||||
++ optional config.primary "primary"
|
++ optional config.primary "primary"
|
||||||
|
|
@ -275,18 +321,23 @@ let
|
||||||
++ optional (config.rate != "") "rate ${config.rate}"
|
++ optional (config.rate != "") "rate ${config.rate}"
|
||||||
++ optional (config.rotate != null) "rotate ${config.rotate}"
|
++ optional (config.rotate != null) "rotate ${config.rotate}"
|
||||||
++ optional (config.filter != null) "filter ${config.filter}"
|
++ optional (config.filter != null) "filter ${config.filter}"
|
||||||
++ optional (config.transform != null) ("transform "
|
++ optional (config.transform != null) (
|
||||||
+ lib.concatMapStringsSep "," toString (lib.flatten config.transform))
|
"transform " + lib.concatMapStringsSep "," toString (lib.flatten config.transform)
|
||||||
++ optional (config.scale != null)
|
)
|
||||||
((if config.scale.method == "factor" then "scale" else "scale-from")
|
++ optional (config.scale != null) (
|
||||||
+ " ${toString config.scale.x}x${toString config.scale.y}")
|
(if config.scale.method == "factor" then "scale" else "scale-from")
|
||||||
++ optional (config.extraConfig != "") config.extraConfig)
|
+ " ${toString config.scale.x}x${toString config.scale.y}"
|
||||||
else ''
|
)
|
||||||
output ${name}
|
++ optional (config.extraConfig != "") config.extraConfig
|
||||||
off
|
)
|
||||||
'';
|
else
|
||||||
|
''
|
||||||
|
output ${name}
|
||||||
|
off
|
||||||
|
'';
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
programs.autorandr = {
|
programs.autorandr = {
|
||||||
enable = lib.mkEnableOption "Autorandr";
|
enable = lib.mkEnableOption "Autorandr";
|
||||||
|
|
@ -358,15 +409,19 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
assertions = lib.flatten (mapAttrsToList (profile:
|
assertions = lib.flatten (
|
||||||
{ config, ... }:
|
mapAttrsToList (
|
||||||
mapAttrsToList (output: opts: {
|
profile:
|
||||||
assertion = opts.scale == null || opts.transform == null;
|
{ config, ... }:
|
||||||
message = ''
|
mapAttrsToList (output: opts: {
|
||||||
Cannot use the profile output options 'scale' and 'transform' simultaneously.
|
assertion = opts.scale == null || opts.transform == null;
|
||||||
Check configuration for: programs.autorandr.profiles.${profile}.config.${output}
|
message = ''
|
||||||
'';
|
Cannot use the profile output options 'scale' and 'transform' simultaneously.
|
||||||
}) config) cfg.profiles);
|
Check configuration for: programs.autorandr.profiles.${profile}.config.${output}
|
||||||
|
'';
|
||||||
|
}) config
|
||||||
|
) cfg.profiles
|
||||||
|
);
|
||||||
|
|
||||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.programs.awscli;
|
cfg = config.programs.awscli;
|
||||||
iniFormat = pkgs.formats.ini { };
|
iniFormat = pkgs.formats.ini { };
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.anthonyroussel ];
|
meta.maintainers = [ lib.maintainers.anthonyroussel ];
|
||||||
|
|
||||||
options.programs.awscli = {
|
options.programs.awscli = {
|
||||||
|
|
@ -55,16 +61,12 @@ in {
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
|
|
||||||
home.file."${config.home.homeDirectory}/.aws/config" =
|
home.file."${config.home.homeDirectory}/.aws/config" = lib.mkIf (cfg.settings != { }) {
|
||||||
lib.mkIf (cfg.settings != { }) {
|
source = iniFormat.generate "aws-config-${config.home.username}" cfg.settings;
|
||||||
source =
|
};
|
||||||
iniFormat.generate "aws-config-${config.home.username}" cfg.settings;
|
|
||||||
};
|
|
||||||
|
|
||||||
home.file."${config.home.homeDirectory}/.aws/credentials" =
|
home.file."${config.home.homeDirectory}/.aws/credentials" = lib.mkIf (cfg.credentials != { }) {
|
||||||
lib.mkIf (cfg.credentials != { }) {
|
source = iniFormat.generate "aws-credentials-${config.home.username}" cfg.credentials;
|
||||||
source = iniFormat.generate "aws-credentials-${config.home.username}"
|
};
|
||||||
cfg.credentials;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,23 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.programs.bacon;
|
cfg = config.programs.bacon;
|
||||||
|
|
||||||
settingsFormat = pkgs.formats.toml { };
|
settingsFormat = pkgs.formats.toml { };
|
||||||
|
|
||||||
configDir = if pkgs.stdenv.isDarwin then
|
configDir =
|
||||||
"Library/Application Support/org.dystroy.bacon"
|
if pkgs.stdenv.isDarwin then
|
||||||
else
|
"Library/Application Support/org.dystroy.bacon"
|
||||||
"${config.xdg.configHome}/bacon";
|
else
|
||||||
|
"${config.xdg.configHome}/bacon";
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.hm.maintainers.shimunn ];
|
meta.maintainers = [ lib.hm.maintainers.shimunn ];
|
||||||
|
|
||||||
options.programs.bacon = {
|
options.programs.bacon = {
|
||||||
|
|
@ -23,7 +30,13 @@ in {
|
||||||
default = { };
|
default = { };
|
||||||
example = {
|
example = {
|
||||||
jobs.default = {
|
jobs.default = {
|
||||||
command = [ "cargo" "build" "--all-features" "--color" "always" ];
|
command = [
|
||||||
|
"cargo"
|
||||||
|
"build"
|
||||||
|
"--all-features"
|
||||||
|
"--color"
|
||||||
|
"always"
|
||||||
|
];
|
||||||
need_stdout = true;
|
need_stdout = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) mkIf mkOption optionalAttrs types;
|
inherit (lib)
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
optionalAttrs
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.programs.bash;
|
cfg = config.programs.bash;
|
||||||
|
|
||||||
writeBashScript = name: text:
|
writeBashScript =
|
||||||
|
name: text:
|
||||||
pkgs.writeTextFile {
|
pkgs.writeTextFile {
|
||||||
inherit name text;
|
inherit name text;
|
||||||
checkPhase = ''
|
checkPhase = ''
|
||||||
|
|
@ -12,15 +23,19 @@ let
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.rycee ];
|
meta.maintainers = [ lib.maintainers.rycee ];
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
(lib.mkRenamedOptionModule [ "programs" "bash" "enableAutojump" ] [
|
(lib.mkRenamedOptionModule
|
||||||
"programs"
|
[ "programs" "bash" "enableAutojump" ]
|
||||||
"autojump"
|
[
|
||||||
"enable"
|
"programs"
|
||||||
])
|
"autojump"
|
||||||
|
"enable"
|
||||||
|
]
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -70,8 +85,14 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
historyControl = mkOption {
|
historyControl = mkOption {
|
||||||
type = types.listOf
|
type = types.listOf (
|
||||||
(types.enum [ "erasedups" "ignoredups" "ignorespace" "ignoreboth" ]);
|
types.enum [
|
||||||
|
"erasedups"
|
||||||
|
"ignoredups"
|
||||||
|
"ignorespace"
|
||||||
|
"ignoreboth"
|
||||||
|
]
|
||||||
|
);
|
||||||
default = [ ];
|
default = [ ];
|
||||||
description = "Controlling how commands are saved on the history list.";
|
description = "Controlling how commands are saved on the history list.";
|
||||||
};
|
};
|
||||||
|
|
@ -79,9 +100,12 @@ in {
|
||||||
historyIgnore = mkOption {
|
historyIgnore = mkOption {
|
||||||
type = types.listOf types.str;
|
type = types.listOf types.str;
|
||||||
default = [ ];
|
default = [ ];
|
||||||
example = [ "ls" "cd" "exit" ];
|
example = [
|
||||||
description =
|
"ls"
|
||||||
"List of commands that should not be saved to the history list.";
|
"cd"
|
||||||
|
"exit"
|
||||||
|
];
|
||||||
|
description = "List of commands that should not be saved to the history list.";
|
||||||
};
|
};
|
||||||
|
|
||||||
shellOptions = mkOption {
|
shellOptions = mkOption {
|
||||||
|
|
@ -101,7 +125,10 @@ in {
|
||||||
# Warn if closing shell with running jobs.
|
# Warn if closing shell with running jobs.
|
||||||
"checkjobs"
|
"checkjobs"
|
||||||
];
|
];
|
||||||
example = [ "extglob" "-cdspell" ];
|
example = [
|
||||||
|
"extglob"
|
||||||
|
"-cdspell"
|
||||||
|
];
|
||||||
description = ''
|
description = ''
|
||||||
Shell options to set. Prefix an option with
|
Shell options to set. Prefix an option with
|
||||||
"`-`" to unset.
|
"`-`" to unset.
|
||||||
|
|
@ -111,7 +138,9 @@ in {
|
||||||
sessionVariables = mkOption {
|
sessionVariables = mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = types.attrs;
|
type = types.attrs;
|
||||||
example = { MAILCHECK = 30; };
|
example = {
|
||||||
|
MAILCHECK = 30;
|
||||||
|
};
|
||||||
description = ''
|
description = ''
|
||||||
Environment variables that will be set for the Bash session.
|
Environment variables that will be set for the Bash session.
|
||||||
'';
|
'';
|
||||||
|
|
@ -170,77 +199,90 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let
|
config =
|
||||||
aliasesStr = lib.concatStringsSep "\n"
|
let
|
||||||
(lib.mapAttrsToList (k: v: "alias ${k}=${lib.escapeShellArg v}")
|
aliasesStr = lib.concatStringsSep "\n" (
|
||||||
cfg.shellAliases);
|
lib.mapAttrsToList (k: v: "alias ${k}=${lib.escapeShellArg v}") cfg.shellAliases
|
||||||
|
);
|
||||||
|
|
||||||
shoptsStr = let switch = v: if lib.hasPrefix "-" v then "-u" else "-s";
|
shoptsStr =
|
||||||
in lib.concatStringsSep "\n"
|
let
|
||||||
(map (v: "shopt ${switch v} ${lib.removePrefix "-" v}") cfg.shellOptions);
|
switch = v: if lib.hasPrefix "-" v then "-u" else "-s";
|
||||||
|
in
|
||||||
|
lib.concatStringsSep "\n" (map (v: "shopt ${switch v} ${lib.removePrefix "-" v}") cfg.shellOptions);
|
||||||
|
|
||||||
sessionVarsStr = config.lib.shell.exportAll cfg.sessionVariables;
|
sessionVarsStr = config.lib.shell.exportAll cfg.sessionVariables;
|
||||||
|
|
||||||
historyControlStr = (lib.concatStringsSep "\n"
|
historyControlStr = (
|
||||||
(lib.mapAttrsToList (n: v: "${n}=${v}")
|
lib.concatStringsSep "\n" (
|
||||||
(optionalAttrs (cfg.historyFileSize != null) {
|
lib.mapAttrsToList (n: v: "${n}=${v}") (
|
||||||
HISTFILESIZE = toString cfg.historyFileSize;
|
optionalAttrs (cfg.historyFileSize != null) {
|
||||||
} // optionalAttrs (cfg.historySize != null) {
|
HISTFILESIZE = toString cfg.historyFileSize;
|
||||||
HISTSIZE = toString cfg.historySize;
|
}
|
||||||
} // optionalAttrs (cfg.historyFile != null) {
|
// optionalAttrs (cfg.historySize != null) {
|
||||||
HISTFILE = ''"${cfg.historyFile}"'';
|
HISTSIZE = toString cfg.historySize;
|
||||||
} // optionalAttrs (cfg.historyControl != [ ]) {
|
}
|
||||||
HISTCONTROL = lib.concatStringsSep ":" cfg.historyControl;
|
// optionalAttrs (cfg.historyFile != null) {
|
||||||
} // optionalAttrs (cfg.historyIgnore != [ ]) {
|
HISTFILE = ''"${cfg.historyFile}"'';
|
||||||
HISTIGNORE =
|
}
|
||||||
lib.escapeShellArg (lib.concatStringsSep ":" cfg.historyIgnore);
|
// optionalAttrs (cfg.historyControl != [ ]) {
|
||||||
}) ++ lib.optional (cfg.historyFile != null)
|
HISTCONTROL = lib.concatStringsSep ":" cfg.historyControl;
|
||||||
''mkdir -p "$(dirname "$HISTFILE")"''));
|
}
|
||||||
in mkIf cfg.enable {
|
// optionalAttrs (cfg.historyIgnore != [ ]) {
|
||||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
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" ''
|
home.file.".bash_profile".source = writeBashScript "bash_profile" ''
|
||||||
# include .profile if it exists
|
# include .profile if it exists
|
||||||
[[ -f ~/.profile ]] && . ~/.profile
|
[[ -f ~/.profile ]] && . ~/.profile
|
||||||
|
|
||||||
# include .bashrc if it exists
|
# include .bashrc if it exists
|
||||||
[[ -f ~/.bashrc ]] && . ~/.bashrc
|
[[ -f ~/.bashrc ]] && . ~/.bashrc
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# If completion is enabled then make sure it is sourced very early. This
|
# If completion is enabled then make sure it is sourced very early. This
|
||||||
# is to avoid problems if any other initialization code attempts to set up
|
# is to avoid problems if any other initialization code attempts to set up
|
||||||
# completion.
|
# completion.
|
||||||
programs.bash.initExtra = mkIf cfg.enableCompletion (lib.mkOrder 100 ''
|
programs.bash.initExtra = mkIf cfg.enableCompletion (
|
||||||
if [[ ! -v BASH_COMPLETION_VERSINFO ]]; then
|
lib.mkOrder 100 ''
|
||||||
. "${pkgs.bash-completion}/etc/profile.d/bash_completion.sh"
|
if [[ ! -v BASH_COMPLETION_VERSINFO ]]; then
|
||||||
fi
|
. "${pkgs.bash-completion}/etc/profile.d/bash_completion.sh"
|
||||||
'');
|
fi
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
home.file.".profile".source = writeBashScript "profile" ''
|
home.file.".profile".source = writeBashScript "profile" ''
|
||||||
. "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh"
|
. "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh"
|
||||||
|
|
||||||
${sessionVarsStr}
|
${sessionVarsStr}
|
||||||
|
|
||||||
${cfg.profileExtra}
|
${cfg.profileExtra}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
home.file.".bashrc".source = writeBashScript "bashrc" ''
|
home.file.".bashrc".source = writeBashScript "bashrc" ''
|
||||||
${cfg.bashrcExtra}
|
${cfg.bashrcExtra}
|
||||||
|
|
||||||
# Commands that should be applied only for interactive shells.
|
# Commands that should be applied only for interactive shells.
|
||||||
[[ $- == *i* ]] || return
|
[[ $- == *i* ]] || return
|
||||||
|
|
||||||
${historyControlStr}
|
${historyControlStr}
|
||||||
|
|
||||||
${shoptsStr}
|
${shoptsStr}
|
||||||
|
|
||||||
${aliasesStr}
|
${aliasesStr}
|
||||||
|
|
||||||
${cfg.initExtra}
|
${cfg.initExtra}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
home.file.".bash_logout" = mkIf (cfg.logoutExtra != "") {
|
home.file.".bash_logout" = mkIf (cfg.logoutExtra != "") {
|
||||||
source = writeBashScript "bash_logout" cfg.logoutExtra;
|
source = writeBashScript "bash_logout" cfg.logoutExtra;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
let cfg = config.programs.bashmount;
|
config,
|
||||||
in {
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.programs.bashmount;
|
||||||
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ lib.maintainers.AndersonTorres ];
|
meta.maintainers = [ lib.maintainers.AndersonTorres ];
|
||||||
|
|
||||||
options.programs.bashmount = {
|
options.programs.bashmount = {
|
||||||
|
|
@ -24,7 +31,6 @@ in {
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
|
|
||||||
xdg.configFile."bashmount/config" =
|
xdg.configFile."bashmount/config" = lib.mkIf (cfg.extraConfig != "") { text = cfg.extraConfig; };
|
||||||
lib.mkIf (cfg.extraConfig != "") { text = cfg.extraConfig; };
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,22 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) literalExpression mkEnableOption mkOption mkIf types;
|
inherit (lib)
|
||||||
|
literalExpression
|
||||||
|
mkEnableOption
|
||||||
|
mkOption
|
||||||
|
mkIf
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.programs.bat;
|
cfg = config.programs.bat;
|
||||||
|
|
||||||
toConfigFile = attrs:
|
toConfigFile =
|
||||||
|
attrs:
|
||||||
let
|
let
|
||||||
inherit (builtins) isBool attrNames;
|
inherit (builtins) isBool attrNames;
|
||||||
nonBoolFlags = lib.filterAttrs (_: v: !(isBool v)) attrs;
|
nonBoolFlags = lib.filterAttrs (_: v: !(isBool v)) attrs;
|
||||||
|
|
@ -17,20 +29,31 @@ let
|
||||||
switches = lib.concatMapStrings (k: ''
|
switches = lib.concatMapStrings (k: ''
|
||||||
--${k}
|
--${k}
|
||||||
'') (attrNames enabledBoolFlags);
|
'') (attrNames enabledBoolFlags);
|
||||||
in keyValuePairs + switches;
|
in
|
||||||
in {
|
keyValuePairs + switches;
|
||||||
|
in
|
||||||
|
{
|
||||||
meta.maintainers = with lib.maintainers; [ khaneliman ];
|
meta.maintainers = with lib.maintainers; [ khaneliman ];
|
||||||
|
|
||||||
options.programs.bat = {
|
options.programs.bat = {
|
||||||
enable = mkEnableOption "bat, a cat clone with wings";
|
enable = mkEnableOption "bat, a cat clone with wings";
|
||||||
|
|
||||||
config = mkOption {
|
config = mkOption {
|
||||||
type = with types; attrsOf (oneOf [ str (listOf str) bool ]);
|
type =
|
||||||
|
with types;
|
||||||
|
attrsOf (oneOf [
|
||||||
|
str
|
||||||
|
(listOf str)
|
||||||
|
bool
|
||||||
|
]);
|
||||||
default = { };
|
default = { };
|
||||||
example = {
|
example = {
|
||||||
theme = "TwoDark";
|
theme = "TwoDark";
|
||||||
pager = "less -FR";
|
pager = "less -FR";
|
||||||
map-syntax = [ "*.jenkinsfile:Groovy" "*.props:Java Properties" ];
|
map-syntax = [
|
||||||
|
"*.jenkinsfile:Groovy"
|
||||||
|
"*.props:Java Properties"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
description = ''
|
description = ''
|
||||||
Bat configuration.
|
Bat configuration.
|
||||||
|
|
@ -40,8 +63,7 @@ in {
|
||||||
extraPackages = mkOption {
|
extraPackages = mkOption {
|
||||||
type = types.listOf types.package;
|
type = types.listOf types.package;
|
||||||
default = [ ];
|
default = [ ];
|
||||||
example = literalExpression
|
example = literalExpression "with pkgs.bat-extras; [ batdiff batman batgrep batwatch ];";
|
||||||
"with pkgs.bat-extras; [ batdiff batman batgrep batwatch ];";
|
|
||||||
description = ''
|
description = ''
|
||||||
Additional bat packages to install.
|
Additional bat packages to install.
|
||||||
'';
|
'';
|
||||||
|
|
@ -50,21 +72,24 @@ in {
|
||||||
package = lib.mkPackageOption pkgs "bat" { };
|
package = lib.mkPackageOption pkgs "bat" { };
|
||||||
|
|
||||||
themes = mkOption {
|
themes = mkOption {
|
||||||
type = types.attrsOf (types.either types.lines (types.submodule {
|
type = types.attrsOf (
|
||||||
options = {
|
types.either types.lines (
|
||||||
src = mkOption {
|
types.submodule {
|
||||||
type = types.path;
|
options = {
|
||||||
description = "Path to the theme folder.";
|
src = mkOption {
|
||||||
};
|
type = types.path;
|
||||||
|
description = "Path to the theme folder.";
|
||||||
|
};
|
||||||
|
|
||||||
file = mkOption {
|
file = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
description =
|
description = "Subpath of the theme file within the source, if needed.";
|
||||||
"Subpath of the theme file within the source, if needed.";
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
}));
|
)
|
||||||
|
);
|
||||||
default = { };
|
default = { };
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
{
|
{
|
||||||
|
|
@ -85,20 +110,23 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
syntaxes = mkOption {
|
syntaxes = mkOption {
|
||||||
type = types.attrsOf (types.either types.lines (types.submodule {
|
type = types.attrsOf (
|
||||||
options = {
|
types.either types.lines (
|
||||||
src = mkOption {
|
types.submodule {
|
||||||
type = types.path;
|
options = {
|
||||||
description = "Path to the syntax folder.";
|
src = mkOption {
|
||||||
};
|
type = types.path;
|
||||||
file = mkOption {
|
description = "Path to the syntax folder.";
|
||||||
type = types.nullOr types.str;
|
};
|
||||||
default = null;
|
file = mkOption {
|
||||||
description =
|
type = types.nullOr types.str;
|
||||||
"Subpath of the syntax file within the source, if needed.";
|
default = null;
|
||||||
};
|
description = "Subpath of the syntax file within the source, if needed.";
|
||||||
};
|
};
|
||||||
}));
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
default = { };
|
default = { };
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
{
|
{
|
||||||
|
|
@ -119,54 +147,75 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable (lib.mkMerge [
|
config = mkIf cfg.enable (
|
||||||
(mkIf (lib.any lib.isString (lib.attrValues cfg.themes)) {
|
lib.mkMerge [
|
||||||
warnings = [''
|
(mkIf (lib.any lib.isString (lib.attrValues cfg.themes)) {
|
||||||
Using programs.bat.themes as a string option is deprecated and will be
|
warnings = [
|
||||||
removed in the future. Please change to using it as an attribute set
|
''
|
||||||
instead.
|
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 = [''
|
];
|
||||||
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
|
(mkIf (lib.any lib.isString (lib.attrValues cfg.syntaxes)) {
|
||||||
instead.
|
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
|
||||||
home.packages = [ cfg.package ] ++ cfg.extraPackages;
|
instead.
|
||||||
|
''
|
||||||
|
];
|
||||||
|
})
|
||||||
|
{
|
||||||
|
home.packages = [ cfg.package ] ++ cfg.extraPackages;
|
||||||
|
|
||||||
xdg.configFile = lib.mkMerge ([{
|
xdg.configFile = lib.mkMerge (
|
||||||
"bat/config" =
|
[
|
||||||
mkIf (cfg.config != { }) { text = toConfigFile cfg.config; };
|
{
|
||||||
}] ++ (lib.flip lib.mapAttrsToList cfg.themes (name: val: {
|
"bat/config" = mkIf (cfg.config != { }) { text = toConfigFile cfg.config; };
|
||||||
"bat/themes/${name}.tmTheme" = if lib.isString val then {
|
}
|
||||||
text = val;
|
]
|
||||||
} else {
|
++ (lib.flip lib.mapAttrsToList cfg.themes (
|
||||||
source =
|
name: val: {
|
||||||
if isNull val.file then "${val.src}" else "${val.src}/${val.file}";
|
"bat/themes/${name}.tmTheme" =
|
||||||
};
|
if lib.isString val then
|
||||||
})) ++ (lib.flip lib.mapAttrsToList cfg.syntaxes (name: val: {
|
{
|
||||||
"bat/syntaxes/${name}.sublime-syntax" = if lib.isString val then {
|
text = val;
|
||||||
text = val;
|
}
|
||||||
} else {
|
else
|
||||||
source =
|
{
|
||||||
if isNull val.file then "${val.src}" else "${val.src}/${val.file}";
|
source = if isNull val.file then "${val.src}" else "${val.src}/${val.file}";
|
||||||
};
|
};
|
||||||
})));
|
}
|
||||||
|
))
|
||||||
|
++ (lib.flip lib.mapAttrsToList cfg.syntaxes (
|
||||||
|
name: val: {
|
||||||
|
"bat/syntaxes/${name}.sublime-syntax" =
|
||||||
|
if lib.isString val then
|
||||||
|
{
|
||||||
|
text = val;
|
||||||
|
}
|
||||||
|
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
|
# NOTE: run `bat cache --build` in an empty directory to work
|
||||||
# around failure when ~/cache exists
|
# around failure when ~/cache exists
|
||||||
# https://github.com/sharkdp/bat/issues/1726
|
# https://github.com/sharkdp/bat/issues/1726
|
||||||
home.activation.batCache = lib.hm.dag.entryAfter [ "linkGeneration" ] ''
|
home.activation.batCache = lib.hm.dag.entryAfter [ "linkGeneration" ] ''
|
||||||
(
|
(
|
||||||
export XDG_CACHE_HOME=${lib.escapeShellArg config.xdg.cacheHome}
|
export XDG_CACHE_HOME=${lib.escapeShellArg config.xdg.cacheHome}
|
||||||
verboseEcho "Rebuilding bat theme cache"
|
verboseEcho "Rebuilding bat theme cache"
|
||||||
cd "${pkgs.emptyDirectory}"
|
cd "${pkgs.emptyDirectory}"
|
||||||
run ${lib.getExe cfg.package} cache --build
|
run ${lib.getExe cfg.package} cache --build
|
||||||
)
|
)
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
]);
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,34 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) literalExpression mkIf mkOption types;
|
inherit (lib)
|
||||||
|
literalExpression
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.programs.beets;
|
cfg = config.programs.beets;
|
||||||
|
|
||||||
yamlFormat = pkgs.formats.yaml { };
|
yamlFormat = pkgs.formats.yaml { };
|
||||||
|
|
||||||
in {
|
in
|
||||||
meta.maintainers = with lib.maintainers; [ rycee Scrumplex ];
|
{
|
||||||
|
meta.maintainers = with lib.maintainers; [
|
||||||
|
rycee
|
||||||
|
Scrumplex
|
||||||
|
];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
programs.beets = {
|
programs.beets = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = if lib.versionAtLeast config.home.stateVersion "19.03" then
|
default =
|
||||||
false
|
if lib.versionAtLeast config.home.stateVersion "19.03" then false else cfg.settings != { };
|
||||||
else
|
|
||||||
cfg.settings != { };
|
|
||||||
defaultText = "false";
|
defaultText = "false";
|
||||||
description = ''
|
description = ''
|
||||||
Whether to enable the beets music library manager. This
|
Whether to enable the beets music library manager. This
|
||||||
|
|
@ -27,8 +39,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
package = lib.mkPackageOption pkgs "beets" {
|
package = lib.mkPackageOption pkgs "beets" {
|
||||||
example =
|
example = "(pkgs.beets.override { pluginOverrides = { beatport.enable = false; }; })";
|
||||||
"(pkgs.beets.override { pluginOverrides = { beatport.enable = false; }; })";
|
|
||||||
extraDescription = ''
|
extraDescription = ''
|
||||||
Can be used to specify extensions.
|
Can be used to specify extensions.
|
||||||
'';
|
'';
|
||||||
|
|
@ -70,8 +81,7 @@ in {
|
||||||
(mkIf cfg.enable {
|
(mkIf cfg.enable {
|
||||||
home.packages = [ cfg.package ];
|
home.packages = [ cfg.package ];
|
||||||
|
|
||||||
xdg.configFile."beets/config.yaml".source =
|
xdg.configFile."beets/config.yaml".source = yamlFormat.generate "beets-config" cfg.settings;
|
||||||
yamlFormat.generate "beets-config" cfg.settings;
|
|
||||||
})
|
})
|
||||||
|
|
||||||
(mkIf (cfg.mpdIntegration.enableStats || cfg.mpdIntegration.enableUpdate) {
|
(mkIf (cfg.mpdIntegration.enableStats || cfg.mpdIntegration.enableUpdate) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
let cfg = config.programs.bemenu;
|
config,
|
||||||
in {
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.programs.bemenu;
|
||||||
|
in
|
||||||
|
{
|
||||||
meta.maintainers = [ ];
|
meta.maintainers = [ ];
|
||||||
|
|
||||||
options.programs.bemenu = {
|
options.programs.bemenu = {
|
||||||
|
|
@ -9,7 +16,13 @@ in {
|
||||||
package = lib.mkPackageOption pkgs "bemenu" { nullable = true; };
|
package = lib.mkPackageOption pkgs "bemenu" { nullable = true; };
|
||||||
|
|
||||||
settings = lib.mkOption {
|
settings = lib.mkOption {
|
||||||
type = with lib.types; attrsOf (oneOf [ str number bool ]);
|
type =
|
||||||
|
with lib.types;
|
||||||
|
attrsOf (oneOf [
|
||||||
|
str
|
||||||
|
number
|
||||||
|
bool
|
||||||
|
]);
|
||||||
default = { };
|
default = { };
|
||||||
example = lib.literalExpression ''
|
example = lib.literalExpression ''
|
||||||
{
|
{
|
||||||
|
|
@ -29,15 +42,13 @@ in {
|
||||||
width-factor = 0.3;
|
width-factor = 0.3;
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
description =
|
description = "Configuration options for bemenu. See {manpage}`bemenu(1)`.";
|
||||||
"Configuration options for bemenu. See {manpage}`bemenu(1)`.";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
assertions = [
|
assertions = [
|
||||||
(lib.hm.assertions.assertPlatform "programs.bemenu" pkgs
|
(lib.hm.assertions.assertPlatform "programs.bemenu" pkgs lib.platforms.linux)
|
||||||
lib.platforms.linux)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) literalExpression mkOption types;
|
inherit (lib) literalExpression mkOption types;
|
||||||
|
|
||||||
|
|
@ -6,24 +11,33 @@ let
|
||||||
|
|
||||||
yamlFormat = pkgs.formats.yaml { };
|
yamlFormat = pkgs.formats.yaml { };
|
||||||
|
|
||||||
mkNullableOption = args:
|
mkNullableOption =
|
||||||
lib.mkOption (args // {
|
args:
|
||||||
type = lib.types.nullOr args.type;
|
lib.mkOption (
|
||||||
default = null;
|
args
|
||||||
});
|
// {
|
||||||
|
type = lib.types.nullOr args.type;
|
||||||
|
default = null;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
cleanRepositories = repos:
|
cleanRepositories =
|
||||||
map (repo:
|
repos:
|
||||||
if builtins.isString repo then {
|
map (
|
||||||
path = repo;
|
repo:
|
||||||
} else
|
if builtins.isString repo then
|
||||||
removeNullValues repo) repos;
|
{
|
||||||
|
path = repo;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
removeNullValues repo
|
||||||
|
) repos;
|
||||||
|
|
||||||
mkRetentionOption = frequency:
|
mkRetentionOption =
|
||||||
|
frequency:
|
||||||
mkNullableOption {
|
mkNullableOption {
|
||||||
type = types.int;
|
type = types.int;
|
||||||
description =
|
description = "Number of ${frequency} archives to keep. Use -1 for no limit.";
|
||||||
"Number of ${frequency} archives to keep. Use -1 for no limit.";
|
|
||||||
example = 3;
|
example = 3;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -56,7 +70,12 @@ let
|
||||||
consistencyCheckModule = types.submodule {
|
consistencyCheckModule = types.submodule {
|
||||||
options = {
|
options = {
|
||||||
name = mkOption {
|
name = mkOption {
|
||||||
type = types.enum [ "repository" "archives" "data" "extract" ];
|
type = types.enum [
|
||||||
|
"repository"
|
||||||
|
"archives"
|
||||||
|
"data"
|
||||||
|
"extract"
|
||||||
|
];
|
||||||
description = "Name of consistency check to run.";
|
description = "Name of consistency check to run.";
|
||||||
example = "repository";
|
example = "repository";
|
||||||
};
|
};
|
||||||
|
|
@ -69,146 +88,151 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
configModule = types.submodule ({ config, ... }: {
|
configModule = types.submodule (
|
||||||
config.location.extraConfig.exclude_from =
|
{ config, ... }:
|
||||||
lib.mkIf config.location.excludeHomeManagerSymlinks
|
{
|
||||||
(lib.mkAfter [ (toString hmExcludeFile) ]);
|
config.location.extraConfig.exclude_from = lib.mkIf config.location.excludeHomeManagerSymlinks (
|
||||||
options = {
|
lib.mkAfter [ (toString hmExcludeFile) ]
|
||||||
location = {
|
);
|
||||||
sourceDirectories = mkNullableOption {
|
options = {
|
||||||
type = types.listOf types.str;
|
location = {
|
||||||
default = null;
|
sourceDirectories = mkNullableOption {
|
||||||
description = ''
|
type = types.listOf types.str;
|
||||||
Directories to backup.
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Directories to backup.
|
||||||
|
|
||||||
Mutually exclusive with [](#opt-programs.borgmatic.backups._name_.location.patterns).
|
Mutually exclusive with [](#opt-programs.borgmatic.backups._name_.location.patterns).
|
||||||
'';
|
'';
|
||||||
example = literalExpression "[config.home.homeDirectory]";
|
example = literalExpression "[config.home.homeDirectory]";
|
||||||
|
};
|
||||||
|
|
||||||
|
patterns = mkNullableOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Patterns to include/exclude.
|
||||||
|
|
||||||
|
See the output of `borg help patterns` for the syntax. Pattern paths
|
||||||
|
are relative to `/` even when a different recursion root is set.
|
||||||
|
|
||||||
|
Mutually exclusive with [](#opt-programs.borgmatic.backups._name_.location.sourceDirectories).
|
||||||
|
'';
|
||||||
|
example = literalExpression ''
|
||||||
|
[
|
||||||
|
"R /home/user"
|
||||||
|
"- home/user/.cache"
|
||||||
|
"- home/user/Downloads"
|
||||||
|
"+ home/user/Videos/Important Video"
|
||||||
|
"- home/user/Videos"
|
||||||
|
]
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
repositories = mkOption {
|
||||||
|
type = types.listOf (types.either types.str repositoryOption);
|
||||||
|
apply = cleanRepositories;
|
||||||
|
example = literalExpression ''
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path" = "ssh://myuser@myrepo.myserver.com/./repo";
|
||||||
|
"label" = "server";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"path" = "/var/lib/backups/local.borg";
|
||||||
|
"label" = "local";
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
List of local or remote repositories with paths and optional labels.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
excludeHomeManagerSymlinks = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Whether to exclude Home Manager generated symbolic links from
|
||||||
|
the backups. This facilitates restoring the whole home
|
||||||
|
directory when the Nix store doesn't contain the latest
|
||||||
|
Home Manager generation.
|
||||||
|
'';
|
||||||
|
default = false;
|
||||||
|
example = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = extraConfigOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
patterns = mkNullableOption {
|
storage = {
|
||||||
type = types.listOf types.str;
|
encryptionPasscommand = mkNullableOption {
|
||||||
default = null;
|
type = types.str;
|
||||||
description = ''
|
description = "Command writing the passphrase to standard output.";
|
||||||
Patterns to include/exclude.
|
example = literalExpression ''"''${pkgs.password-store}/bin/pass borg-repo"'';
|
||||||
|
};
|
||||||
See the output of `borg help patterns` for the syntax. Pattern paths
|
extraConfig = extraConfigOption;
|
||||||
are relative to `/` even when a different recursion root is set.
|
|
||||||
|
|
||||||
Mutually exclusive with [](#opt-programs.borgmatic.backups._name_.location.sourceDirectories).
|
|
||||||
'';
|
|
||||||
example = literalExpression ''
|
|
||||||
[
|
|
||||||
"R /home/user"
|
|
||||||
"- home/user/.cache"
|
|
||||||
"- home/user/Downloads"
|
|
||||||
"+ home/user/Videos/Important Video"
|
|
||||||
"- home/user/Videos"
|
|
||||||
]
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
repositories = mkOption {
|
retention = {
|
||||||
type = types.listOf (types.either types.str repositoryOption);
|
keepWithin = mkNullableOption {
|
||||||
apply = cleanRepositories;
|
type = types.strMatching "[[:digit:]]+[Hdwmy]";
|
||||||
example = literalExpression ''
|
description = "Keep all archives within this time interval.";
|
||||||
[
|
example = "2d";
|
||||||
{
|
};
|
||||||
"path" = "ssh://myuser@myrepo.myserver.com/./repo";
|
|
||||||
"label" = "server";
|
keepSecondly = mkRetentionOption "secondly";
|
||||||
}
|
keepMinutely = mkRetentionOption "minutely";
|
||||||
{
|
keepHourly = mkRetentionOption "hourly";
|
||||||
"path" = "/var/lib/backups/local.borg";
|
keepDaily = mkRetentionOption "daily";
|
||||||
"label" = "local";
|
keepWeekly = mkRetentionOption "weekly";
|
||||||
}
|
keepMonthly = mkRetentionOption "monthly";
|
||||||
]
|
keepYearly = mkRetentionOption "yearly";
|
||||||
'';
|
|
||||||
description = ''
|
extraConfig = extraConfigOption;
|
||||||
List of local or remote repositories with paths and optional labels.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
excludeHomeManagerSymlinks = mkOption {
|
consistency = {
|
||||||
type = types.bool;
|
checks = mkOption {
|
||||||
description = ''
|
type = types.listOf consistencyCheckModule;
|
||||||
Whether to exclude Home Manager generated symbolic links from
|
default = [ ];
|
||||||
the backups. This facilitates restoring the whole home
|
description = "Consistency checks to run";
|
||||||
directory when the Nix store doesn't contain the latest
|
example = literalExpression ''
|
||||||
Home Manager generation.
|
[
|
||||||
'';
|
{
|
||||||
default = false;
|
name = "repository";
|
||||||
example = true;
|
frequency = "2 weeks";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "archives";
|
||||||
|
frequency = "4 weeks";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "data";
|
||||||
|
frequency = "6 weeks";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "extract";
|
||||||
|
frequency = "6 weeks";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = extraConfigOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
extraConfig = extraConfigOption;
|
output = {
|
||||||
|
extraConfig = extraConfigOption;
|
||||||
|
};
|
||||||
|
|
||||||
|
hooks = {
|
||||||
|
extraConfig = extraConfigOption;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
storage = {
|
removeNullValues = attrSet: lib.filterAttrs (key: value: value != null) attrSet;
|
||||||
encryptionPasscommand = mkNullableOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "Command writing the passphrase to standard output.";
|
|
||||||
example =
|
|
||||||
literalExpression ''"''${pkgs.password-store}/bin/pass borg-repo"'';
|
|
||||||
};
|
|
||||||
extraConfig = extraConfigOption;
|
|
||||||
};
|
|
||||||
|
|
||||||
retention = {
|
|
||||||
keepWithin = mkNullableOption {
|
|
||||||
type = types.strMatching "[[:digit:]]+[Hdwmy]";
|
|
||||||
description = "Keep all archives within this time interval.";
|
|
||||||
example = "2d";
|
|
||||||
};
|
|
||||||
|
|
||||||
keepSecondly = mkRetentionOption "secondly";
|
|
||||||
keepMinutely = mkRetentionOption "minutely";
|
|
||||||
keepHourly = mkRetentionOption "hourly";
|
|
||||||
keepDaily = mkRetentionOption "daily";
|
|
||||||
keepWeekly = mkRetentionOption "weekly";
|
|
||||||
keepMonthly = mkRetentionOption "monthly";
|
|
||||||
keepYearly = mkRetentionOption "yearly";
|
|
||||||
|
|
||||||
extraConfig = extraConfigOption;
|
|
||||||
};
|
|
||||||
|
|
||||||
consistency = {
|
|
||||||
checks = mkOption {
|
|
||||||
type = types.listOf consistencyCheckModule;
|
|
||||||
default = [ ];
|
|
||||||
description = "Consistency checks to run";
|
|
||||||
example = literalExpression ''
|
|
||||||
[
|
|
||||||
{
|
|
||||||
name = "repository";
|
|
||||||
frequency = "2 weeks";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
name = "archives";
|
|
||||||
frequency = "4 weeks";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
name = "data";
|
|
||||||
frequency = "6 weeks";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
name = "extract";
|
|
||||||
frequency = "6 weeks";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
extraConfig = extraConfigOption;
|
|
||||||
};
|
|
||||||
|
|
||||||
output = { extraConfig = extraConfigOption; };
|
|
||||||
|
|
||||||
hooks = { extraConfig = extraConfigOption; };
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
removeNullValues = attrSet:
|
|
||||||
lib.filterAttrs (key: value: value != null) attrSet;
|
|
||||||
|
|
||||||
hmFiles = builtins.attrValues config.home.file;
|
hmFiles = builtins.attrValues config.home.file;
|
||||||
hmSymlinks = (lib.filter (file: !file.recursive) hmFiles);
|
hmSymlinks = (lib.filter (file: !file.recursive) hmFiles);
|
||||||
|
|
@ -218,25 +242,35 @@ let
|
||||||
hmExcludePatterns = lib.concatMapStrings hmExcludePattern hmSymlinks;
|
hmExcludePatterns = lib.concatMapStrings hmExcludePattern hmSymlinks;
|
||||||
hmExcludeFile = pkgs.writeText "hm-symlinks.txt" hmExcludePatterns;
|
hmExcludeFile = pkgs.writeText "hm-symlinks.txt" hmExcludePatterns;
|
||||||
|
|
||||||
writeConfig = config:
|
writeConfig =
|
||||||
lib.generators.toYAML { } (removeNullValues ({
|
config:
|
||||||
source_directories = config.location.sourceDirectories;
|
lib.generators.toYAML { } (
|
||||||
patterns = config.location.patterns;
|
removeNullValues (
|
||||||
repositories = config.location.repositories;
|
{
|
||||||
encryption_passcommand = config.storage.encryptionPasscommand;
|
source_directories = config.location.sourceDirectories;
|
||||||
keep_within = config.retention.keepWithin;
|
patterns = config.location.patterns;
|
||||||
keep_secondly = config.retention.keepSecondly;
|
repositories = config.location.repositories;
|
||||||
keep_minutely = config.retention.keepMinutely;
|
encryption_passcommand = config.storage.encryptionPasscommand;
|
||||||
keep_hourly = config.retention.keepHourly;
|
keep_within = config.retention.keepWithin;
|
||||||
keep_daily = config.retention.keepDaily;
|
keep_secondly = config.retention.keepSecondly;
|
||||||
keep_weekly = config.retention.keepWeekly;
|
keep_minutely = config.retention.keepMinutely;
|
||||||
keep_monthly = config.retention.keepMonthly;
|
keep_hourly = config.retention.keepHourly;
|
||||||
keep_yearly = config.retention.keepYearly;
|
keep_daily = config.retention.keepDaily;
|
||||||
checks = config.consistency.checks;
|
keep_weekly = config.retention.keepWeekly;
|
||||||
} // config.location.extraConfig // config.storage.extraConfig
|
keep_monthly = config.retention.keepMonthly;
|
||||||
// config.retention.extraConfig // config.consistency.extraConfig
|
keep_yearly = config.retention.keepYearly;
|
||||||
// config.output.extraConfig // config.hooks.extraConfig));
|
checks = config.consistency.checks;
|
||||||
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 ];
|
meta.maintainers = [ lib.maintainers.DamienCassou ];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -272,25 +306,28 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
assertions = (lib.mapAttrsToList (backup: opts: {
|
assertions =
|
||||||
assertion = opts.location.sourceDirectories == null
|
(lib.mapAttrsToList (backup: opts: {
|
||||||
|| opts.location.patterns == null;
|
assertion = opts.location.sourceDirectories == null || opts.location.patterns == null;
|
||||||
message = ''
|
message = ''
|
||||||
Borgmatic backup configuration "${backup}" cannot specify both 'location.sourceDirectories' and 'location.patterns'.
|
Borgmatic backup configuration "${backup}" cannot specify both 'location.sourceDirectories' and 'location.patterns'.
|
||||||
'';
|
'';
|
||||||
}) cfg.backups) ++ (lib.mapAttrsToList (backup: opts: {
|
}) cfg.backups)
|
||||||
assertion = !(opts.location.sourceDirectories == null
|
++ (lib.mapAttrsToList (backup: opts: {
|
||||||
&& opts.location.patterns == null);
|
assertion = !(opts.location.sourceDirectories == null && opts.location.patterns == null);
|
||||||
message = ''
|
message = ''
|
||||||
Borgmatic backup configuration "${backup}" must specify one of 'location.sourceDirectories' or 'location.patterns'.
|
Borgmatic backup configuration "${backup}" must specify one of 'location.sourceDirectories' or 'location.patterns'.
|
||||||
'';
|
'';
|
||||||
}) cfg.backups);
|
}) cfg.backups);
|
||||||
|
|
||||||
xdg.configFile = with lib.attrsets;
|
xdg.configFile =
|
||||||
mapAttrs' (configName: config:
|
with lib.attrsets;
|
||||||
|
mapAttrs' (
|
||||||
|
configName: config:
|
||||||
nameValuePair ("borgmatic.d/" + configName + ".yaml") {
|
nameValuePair ("borgmatic.d/" + configName + ".yaml") {
|
||||||
text = writeConfig config;
|
text = writeConfig config;
|
||||||
}) cfg.backups;
|
}
|
||||||
|
) cfg.backups;
|
||||||
|
|
||||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.programs.bottom;
|
cfg = config.programs.bottom;
|
||||||
|
|
||||||
tomlFormat = pkgs.formats.toml { };
|
tomlFormat = pkgs.formats.toml { };
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
programs.bottom = {
|
programs.bottom = {
|
||||||
enable = lib.mkEnableOption ''
|
enable = lib.mkEnableOption ''
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) literalExpression mkOption types;
|
inherit (lib) literalExpression mkOption types;
|
||||||
|
|
||||||
|
|
@ -37,7 +42,10 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
mode = mkOption {
|
mode = mkOption {
|
||||||
type = types.enum [ "file" "directory" ];
|
type = types.enum [
|
||||||
|
"file"
|
||||||
|
"directory"
|
||||||
|
];
|
||||||
default = "directory";
|
default = "directory";
|
||||||
description = ''
|
description = ''
|
||||||
Does the current path redirect a file or a directory?
|
Does the current path redirect a file or a directory?
|
||||||
|
|
@ -81,7 +89,8 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options.programs.boxxy = {
|
options.programs.boxxy = {
|
||||||
enable = lib.mkEnableOption "boxxy: Boxes in badly behaving applications";
|
enable = lib.mkEnableOption "boxxy: Boxes in badly behaving applications";
|
||||||
|
|
||||||
|
|
@ -96,13 +105,11 @@ in {
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
assertions = [
|
assertions = [
|
||||||
(lib.hm.assertions.assertPlatform "programs.boxxy" pkgs
|
(lib.hm.assertions.assertPlatform "programs.boxxy" pkgs lib.platforms.linux)
|
||||||
lib.platforms.linux)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
home.file = lib.mkIf (cfg.rules != [ ]) {
|
home.file = lib.mkIf (cfg.rules != [ ]) {
|
||||||
"${configPath}".source =
|
"${configPath}".source = settingsFormat.generate "boxxy-config.yaml" { rules = cfg.rules; };
|
||||||
settingsFormat.generate "boxxy-config.yaml" { rules = cfg.rules; };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||||
|
|
@ -110,4 +117,3 @@ in {
|
||||||
|
|
||||||
meta.maintainers = with lib.hm.maintainers; [ nikp123 ];
|
meta.maintainers = with lib.hm.maintainers; [ nikp123 ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,17 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) literalExpression mkIf mkOption mkRenamedOptionModule types;
|
inherit (lib)
|
||||||
|
literalExpression
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
mkRenamedOptionModule
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
cfg = config.programs.broot;
|
cfg = config.programs.broot;
|
||||||
|
|
||||||
|
|
@ -13,7 +24,15 @@ let
|
||||||
modal = lib.mkEnableOption "modal (vim) mode";
|
modal = lib.mkEnableOption "modal (vim) mode";
|
||||||
|
|
||||||
verbs = mkOption {
|
verbs = mkOption {
|
||||||
type = with types; listOf (attrsOf (oneOf [ bool str (listOf str) ]));
|
type =
|
||||||
|
with types;
|
||||||
|
listOf (
|
||||||
|
attrsOf (oneOf [
|
||||||
|
bool
|
||||||
|
str
|
||||||
|
(listOf str)
|
||||||
|
])
|
||||||
|
);
|
||||||
default = [ ];
|
default = [ ];
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
[
|
[
|
||||||
|
|
@ -116,53 +135,64 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
shellInit = shell:
|
shellInit =
|
||||||
|
shell:
|
||||||
# Using mkAfter to make it more likely to appear after other
|
# Using mkAfter to make it more likely to appear after other
|
||||||
# manipulations of the prompt.
|
# manipulations of the prompt.
|
||||||
lib.mkAfter ''
|
lib.mkAfter ''
|
||||||
source ${
|
source ${
|
||||||
pkgs.runCommand "br.${shell}" { nativeBuildInputs = [ cfg.package ]; }
|
pkgs.runCommand "br.${shell}" {
|
||||||
"broot --print-shell-function ${shell} > $out"
|
nativeBuildInputs = [ cfg.package ];
|
||||||
|
} "broot --print-shell-function ${shell} > $out"
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
in {
|
in
|
||||||
meta.maintainers = [ lib.hm.maintainers.aheaume lib.maintainers.dermetfan ];
|
{
|
||||||
|
meta.maintainers = [
|
||||||
|
lib.hm.maintainers.aheaume
|
||||||
|
lib.maintainers.dermetfan
|
||||||
|
];
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
(mkRenamedOptionModule [ "programs" "broot" "modal" ] [
|
(mkRenamedOptionModule
|
||||||
"programs"
|
[ "programs" "broot" "modal" ]
|
||||||
"broot"
|
[
|
||||||
"settings"
|
"programs"
|
||||||
"modal"
|
"broot"
|
||||||
])
|
"settings"
|
||||||
(mkRenamedOptionModule [ "programs" "broot" "verbs" ] [
|
"modal"
|
||||||
"programs"
|
]
|
||||||
"broot"
|
)
|
||||||
"settings"
|
(mkRenamedOptionModule
|
||||||
"verbs"
|
[ "programs" "broot" "verbs" ]
|
||||||
])
|
[
|
||||||
(mkRenamedOptionModule [ "programs" "broot" "skin" ] [
|
"programs"
|
||||||
"programs"
|
"broot"
|
||||||
"broot"
|
"settings"
|
||||||
"settings"
|
"verbs"
|
||||||
"skin"
|
]
|
||||||
])
|
)
|
||||||
|
(mkRenamedOptionModule
|
||||||
|
[ "programs" "broot" "skin" ]
|
||||||
|
[
|
||||||
|
"programs"
|
||||||
|
"broot"
|
||||||
|
"settings"
|
||||||
|
"skin"
|
||||||
|
]
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
options.programs.broot = {
|
options.programs.broot = {
|
||||||
enable = lib.mkEnableOption "Broot, a better way to navigate directories";
|
enable = lib.mkEnableOption "Broot, a better way to navigate directories";
|
||||||
|
|
||||||
enableBashIntegration =
|
enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { inherit config; };
|
||||||
lib.hm.shell.mkBashIntegrationOption { inherit config; };
|
|
||||||
|
|
||||||
enableFishIntegration =
|
enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { inherit config; };
|
||||||
lib.hm.shell.mkFishIntegrationOption { inherit config; };
|
|
||||||
|
|
||||||
enableNushellIntegration =
|
enableNushellIntegration = lib.hm.shell.mkNushellIntegrationOption { inherit config; };
|
||||||
lib.hm.shell.mkNushellIntegrationOption { inherit config; };
|
|
||||||
|
|
||||||
enableZshIntegration =
|
enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; };
|
||||||
lib.hm.shell.mkZshIntegrationOption { inherit config; };
|
|
||||||
|
|
||||||
package = lib.mkPackageOption pkgs "broot" { };
|
package = lib.mkPackageOption pkgs "broot" { };
|
||||||
|
|
||||||
|
|
@ -190,9 +220,7 @@ in {
|
||||||
postBuild = ''
|
postBuild = ''
|
||||||
rm $out/conf.hjson
|
rm $out/conf.hjson
|
||||||
${lib.getExe pkgs.jq} --slurp add > $out/conf.hjson \
|
${lib.getExe pkgs.jq} --slurp add > $out/conf.hjson \
|
||||||
<(${
|
<(${lib.getExe pkgs.hjson-go} -c ${cfg.package.src}/resources/default-conf/conf.hjson) \
|
||||||
lib.getExe pkgs.hjson-go
|
|
||||||
} -c ${cfg.package.src}/resources/default-conf/conf.hjson) \
|
|
||||||
${jsonFormat.generate "broot-config.json" cfg.settings}
|
${jsonFormat.generate "broot-config.json" cfg.settings}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
@ -205,8 +233,7 @@ in {
|
||||||
|
|
||||||
fish.shellInit = mkIf cfg.enableFishIntegration (shellInit "fish");
|
fish.shellInit = mkIf cfg.enableFishIntegration (shellInit "fish");
|
||||||
|
|
||||||
nushell.extraConfig =
|
nushell.extraConfig = mkIf cfg.enableNushellIntegration (shellInit "nushell");
|
||||||
mkIf cfg.enableNushellIntegration (shellInit "nushell");
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,21 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
cfg = config.programs.browserpass;
|
cfg = config.programs.browserpass;
|
||||||
browsers = [ "brave" "chrome" "chromium" "firefox" "librewolf" "vivaldi" ];
|
browsers = [
|
||||||
in {
|
"brave"
|
||||||
|
"chrome"
|
||||||
|
"chromium"
|
||||||
|
"firefox"
|
||||||
|
"librewolf"
|
||||||
|
"vivaldi"
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
programs.browserpass = {
|
programs.browserpass = {
|
||||||
enable = lib.mkEnableOption "the browserpass extension host application";
|
enable = lib.mkEnableOption "the browserpass extension host application";
|
||||||
|
|
@ -17,82 +30,108 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
home.file = lib.foldl' (a: b: a // b) { } (lib.concatMap (x:
|
home.file = lib.foldl' (a: b: a // b) { } (
|
||||||
with pkgs.stdenv;
|
lib.concatMap (
|
||||||
if x == "brave" then
|
x:
|
||||||
let
|
with pkgs.stdenv;
|
||||||
dir = if isDarwin then
|
if x == "brave" then
|
||||||
"Library/Application Support/BraveSoftware/Brave-Browser/NativeMessagingHosts"
|
let
|
||||||
else
|
dir =
|
||||||
".config/BraveSoftware/Brave-Browser/NativeMessagingHosts";
|
if isDarwin then
|
||||||
in [{
|
"Library/Application Support/BraveSoftware/Brave-Browser/NativeMessagingHosts"
|
||||||
# Policies are read from `/etc/brave/policies` only
|
else
|
||||||
# https://github.com/brave/brave-browser/issues/19052
|
".config/BraveSoftware/Brave-Browser/NativeMessagingHosts";
|
||||||
"${dir}/com.github.browserpass.native.json".source =
|
in
|
||||||
"${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json";
|
[
|
||||||
}]
|
{
|
||||||
else if x == "chrome" then
|
# Policies are read from `/etc/brave/policies` only
|
||||||
let
|
# https://github.com/brave/brave-browser/issues/19052
|
||||||
dir = if isDarwin then
|
"${dir}/com.github.browserpass.native.json".source =
|
||||||
"Library/Application Support/Google/Chrome/NativeMessagingHosts"
|
"${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json";
|
||||||
else
|
}
|
||||||
".config/google-chrome/NativeMessagingHosts";
|
]
|
||||||
in [{
|
else if x == "chrome" then
|
||||||
"${dir}/com.github.browserpass.native.json".source =
|
let
|
||||||
"${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json";
|
dir =
|
||||||
"${dir}/../policies/managed/com.github.browserpass.native.json".source =
|
if isDarwin then
|
||||||
"${pkgs.browserpass}/lib/browserpass/policies/chromium/com.github.browserpass.native.json";
|
"Library/Application Support/Google/Chrome/NativeMessagingHosts"
|
||||||
}]
|
else
|
||||||
else if x == "chromium" then
|
".config/google-chrome/NativeMessagingHosts";
|
||||||
let
|
in
|
||||||
dir = if isDarwin then
|
[
|
||||||
"Library/Application Support/Chromium/NativeMessagingHosts"
|
{
|
||||||
else
|
"${dir}/com.github.browserpass.native.json".source =
|
||||||
".config/chromium/NativeMessagingHosts";
|
"${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json";
|
||||||
in [
|
"${dir}/../policies/managed/com.github.browserpass.native.json".source =
|
||||||
{
|
"${pkgs.browserpass}/lib/browserpass/policies/chromium/com.github.browserpass.native.json";
|
||||||
"${dir}/com.github.browserpass.native.json".source =
|
}
|
||||||
"${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json";
|
]
|
||||||
}
|
else if x == "chromium" then
|
||||||
{
|
let
|
||||||
"${dir}/../policies/managed/com.github.browserpass.native.json".source =
|
dir =
|
||||||
"${pkgs.browserpass}/lib/browserpass/policies/chromium/com.github.browserpass.native.json";
|
if isDarwin then
|
||||||
}
|
"Library/Application Support/Chromium/NativeMessagingHosts"
|
||||||
]
|
else
|
||||||
else if x == "firefox" then
|
".config/chromium/NativeMessagingHosts";
|
||||||
let
|
in
|
||||||
dir = if isDarwin then
|
[
|
||||||
"Library/Application Support/Mozilla/NativeMessagingHosts"
|
{
|
||||||
else
|
"${dir}/com.github.browserpass.native.json".source =
|
||||||
".mozilla/native-messaging-hosts";
|
"${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json";
|
||||||
in [{
|
}
|
||||||
"${dir}/com.github.browserpass.native.json".source =
|
{
|
||||||
"${pkgs.browserpass}/lib/browserpass/hosts/firefox/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 == "librewolf" then
|
}
|
||||||
let
|
]
|
||||||
dir = if isDarwin then
|
else if x == "firefox" then
|
||||||
"Library/Application Support/LibreWolf/NativeMessagingHosts"
|
let
|
||||||
else
|
dir =
|
||||||
".librewolf/native-messaging-hosts";
|
if isDarwin then
|
||||||
in [{
|
"Library/Application Support/Mozilla/NativeMessagingHosts"
|
||||||
"${dir}/com.github.browserpass.native.json".source =
|
else
|
||||||
"${pkgs.browserpass}/lib/browserpass/hosts/firefox/com.github.browserpass.native.json";
|
".mozilla/native-messaging-hosts";
|
||||||
}]
|
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
|
||||||
|
"Library/Application Support/LibreWolf/NativeMessagingHosts"
|
||||||
|
else
|
||||||
|
".librewolf/native-messaging-hosts";
|
||||||
|
in
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"${dir}/com.github.browserpass.native.json".source =
|
||||||
|
"${pkgs.browserpass}/lib/browserpass/hosts/firefox/com.github.browserpass.native.json";
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
else if x == "vivaldi" then
|
else if x == "vivaldi" then
|
||||||
let
|
let
|
||||||
dir = if isDarwin then
|
dir =
|
||||||
"Library/Application Support/Vivaldi/NativeMessagingHosts"
|
if isDarwin then
|
||||||
else
|
"Library/Application Support/Vivaldi/NativeMessagingHosts"
|
||||||
".config/vivaldi/NativeMessagingHosts";
|
else
|
||||||
in [{
|
".config/vivaldi/NativeMessagingHosts";
|
||||||
"${dir}/com.github.browserpass.native.json".source =
|
in
|
||||||
"${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";
|
"${dir}/com.github.browserpass.native.json".source =
|
||||||
}]
|
"${pkgs.browserpass}/lib/browserpass/hosts/chromium/com.github.browserpass.native.json";
|
||||||
else
|
"${dir}/../policies/managed/com.github.browserpass.native.json".source =
|
||||||
throw "unknown browser ${x}") cfg.browsers);
|
"${pkgs.browserpass}/lib/browserpass/policies/chromium/com.github.browserpass.native.json";
|
||||||
|
}
|
||||||
|
]
|
||||||
|
else
|
||||||
|
throw "unknown browser ${x}"
|
||||||
|
) cfg.browsers
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue