treewide: reformat nixfmt-rfc-style

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

View file

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

View file

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

View file

@ -2,7 +2,12 @@
#
# https://github.com/NixOS/nixpkgs/blob/23.11/nixos/modules/config/fonts/fontconfig.nix
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
let
@ -10,15 +15,19 @@ let
profileDirectory = config.home.profileDirectory;
in {
in
{
meta.maintainers = [ lib.maintainers.rycee ];
imports = [
(lib.mkRenamedOptionModule [ "fonts" "fontconfig" "enableProfileFonts" ] [
"fonts"
"fontconfig"
"enable"
])
(lib.mkRenamedOptionModule
[ "fonts" "fontconfig" "enableProfileFonts" ]
[
"fonts"
"fontconfig"
"enable"
]
)
];
options = {
@ -117,53 +126,58 @@ in {
fi
'';
xdg.configFile = let
mkFontconfigConf = conf: ''
<?xml version='1.0'?>
xdg.configFile =
let
mkFontconfigConf = conf: ''
<?xml version='1.0'?>
<!-- Generated by Home Manager. -->
<!-- Generated by Home Manager. -->
<!DOCTYPE fontconfig SYSTEM 'urn:fontconfig:fonts.dtd'>
<fontconfig>
${conf}
</fontconfig>
'';
in {
"fontconfig/conf.d/10-hm-fonts.conf".text = mkFontconfigConf ''
<description>Add fonts in the Nix user profile</description>
<!DOCTYPE fontconfig SYSTEM 'urn:fontconfig:fonts.dtd'>
<fontconfig>
${conf}
</fontconfig>
'';
in
{
"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/fonts.conf</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>
<dir>${config.home.path}/lib/X11/fonts</dir>
<dir>${config.home.path}/share/fonts</dir>
<dir>${profileDirectory}/lib/X11/fonts</dir>
<dir>${profileDirectory}/share/fonts</dir>
<dir>${config.home.path}/lib/X11/fonts</dir>
<dir>${config.home.path}/share/fonts</dir>
<dir>${profileDirectory}/lib/X11/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
genDefault = fonts: name:
lib.optionalString (fonts != [ ]) ''
<alias binding="same">
<family>${name}</family>
<prefer>
${
lib.concatStringsSep "" (map (font: ''
<family>${font}</family>
'') fonts)
}
</prefer>
</alias>
"fontconfig/conf.d/52-hm-default-fonts.conf".text =
let
genDefault =
fonts: name:
lib.optionalString (fonts != [ ]) ''
<alias binding="same">
<family>${name}</family>
<prefer>
${lib.concatStringsSep "" (
map (font: ''
<family>${font}</family>
'') fonts
)}
</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"}
'';
};
};
};
}

View file

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

View file

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

View file

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

View file

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

View file

@ -1,13 +1,23 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
let
cfg = config.nixGL;
wrapperListMarkdown = with builtins;
foldl' (list: name:
list + ''
wrapperListMarkdown =
with builtins;
foldl' (
list: name:
list
+ ''
- ${name}
'') "" (attrNames config.lib.nixGL.wrappers);
in {
''
) "" (attrNames config.lib.nixGL.wrappers);
in
{
meta.maintainers = [ lib.maintainers.smona ];
options.nixGL = {
@ -93,7 +103,12 @@ in {
};
prime.installScript = lib.mkOption {
type = with lib.types; nullOr (enum [ "mesa" "nvidia" ]);
type =
with lib.types;
nullOr (enum [
"mesa"
"nvidia"
]);
default = null;
example = "mesa";
description = ''
@ -109,10 +124,12 @@ in {
};
installScripts = lib.mkOption {
type = with lib.types;
nullOr (listOf (enum (builtins.attrNames config.lib.nixGL.wrappers)));
type = with lib.types; nullOr (listOf (enum (builtins.attrNames config.lib.nixGL.wrappers)));
default = null;
example = [ "mesa" "mesaPrime" ];
example = [
"mesa"
"mesaPrime"
];
description = ''
For each wrapper `wrp` named in the provided list, a wrapper script
named `nixGLWrp` is installed into the environment. These scripts are
@ -137,168 +154,199 @@ in {
};
};
config = let
findWrapperPackage = packageAttr:
# NixGL has wrapper packages in different places depending on how you
# access it. We want HM configuration to be the same, regardless of how
# NixGL is imported.
#
# First, let's see if we have a flake.
if builtins.hasAttr pkgs.system cfg.packages then
cfg.packages.${pkgs.system}.${packageAttr}
else
# Next, let's see if we have a channel.
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)
config =
let
findWrapperPackage =
packageAttr:
# NixGL has wrapper packages in different places depending on how you
# access it. We want HM configuration to be the same, regardless of how
# NixGL is imported.
#
# First, let's see if we have a flake.
if builtins.hasAttr pkgs.system cfg.packages then
cfg.packages.${pkgs.system}.${packageAttr}
else
(envVarsAsScript nvOffloadEnv)}
exec "$@"
''))
# Next, let's see if we have a channel.
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" ''
exec ${getWrapperExe "Intel"} "$@"
''))
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}";
(lib.mkIf (wantsWrapper "mesaPrime")
(pkgs.writeShellScriptBin "nixGLMesaPrime" ''
${envVarsAsScript mesaOffloadEnv}
exec ${getWrapperExe "Intel"} "$@"
''))
mesaOffloadEnv = {
"DRI_PRIME" = "${cfg.prime.card}";
};
(lib.mkIf (wantsWrapper "nvidia")
(pkgs.writeShellScriptBin "nixGLNvidia" ''
exec ${getWrapperExe "Nvidia"} "$@"
''))
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
{ }
);
(lib.mkIf (wantsWrapper "nvidia")
(pkgs.writeShellScriptBin "nixGLNvidiaPrime" ''
${envVarsAsScript nvOffloadEnv}
exec ${getWrapperExe "Nvidia"} "$@"
''))
];
};
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
(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"} "$@"
''
))
];
};
}

View file

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

View file

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

View file

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

View file

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

View file

@ -1,13 +1,27 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
let
cfg = config.qt;
# Map platform names to their packages.
platformPackages = with pkgs; {
gnome = [ qgnomeplatform qgnomeplatform-qt6 ];
adwaita = [ qadwaitadecorations qadwaitadecorations-qt6 ];
gtk = [ libsForQt5.qtstyleplugins qt6Packages.qt6gtk2 ];
gnome = [
qgnomeplatform
qgnomeplatform-qt6
];
adwaita = [
qadwaitadecorations
qadwaitadecorations-qt6
];
gtk = [
libsForQt5.qtstyleplugins
qt6Packages.qt6gtk2
];
kde = [
libsForQt5.kio
libsForQt5.plasma-integration
@ -18,8 +32,14 @@ let
kdePackages.plasma-integration
kdePackages.systemsettings
];
lxqt = [ lxqt.lxqt-qtplugin lxqt.lxqt-config ];
qtct = [ libsForQt5.qt5ct qt6Packages.qt6ct ];
lxqt = [
lxqt.lxqt-qtplugin
lxqt.lxqt-config
];
qtct = [
libsForQt5.qt5ct
qt6Packages.qt6ct
];
};
# Maps style names to their QT_QPA_PLATFORMTHEME, if necessary.
@ -34,122 +54,181 @@ let
bb10bright = libsForQt5.qtstyleplugins;
bb10dark = libsForQt5.qtstyleplugins;
cleanlooks = libsForQt5.qtstyleplugins;
gtk2 = [ libsForQt5.qtstyleplugins qt6Packages.qt6gtk2 ];
gtk2 = [
libsForQt5.qtstyleplugins
qt6Packages.qt6gtk2
];
motif = libsForQt5.qtstyleplugins;
cde = libsForQt5.qtstyleplugins;
plastique = libsForQt5.qtstyleplugins;
adwaita = [ adwaita-qt adwaita-qt6 ];
adwaita-dark = [ adwaita-qt adwaita-qt6 ];
adwaita-highcontrast = [ adwaita-qt adwaita-qt6 ];
adwaita-highcontrastinverse = [ adwaita-qt adwaita-qt6 ];
adwaita = [
adwaita-qt
adwaita-qt6
];
adwaita-dark = [
adwaita-qt
adwaita-qt6
];
adwaita-highcontrast = [
adwaita-qt
adwaita-qt6
];
adwaita-highcontrastinverse = [
adwaita-qt
adwaita-qt6
];
breeze = libsForQt5.breeze-qt5;
kvantum =
[ libsForQt5.qtstyleplugin-kvantum qt6Packages.qtstyleplugin-kvantum ];
kvantum = [
libsForQt5.qtstyleplugin-kvantum
qt6Packages.qtstyleplugin-kvantum
];
};
in {
meta.maintainers = with lib.maintainers; [ rycee thiagokokada ];
in
{
meta.maintainers = with lib.maintainers; [
rycee
thiagokokada
];
imports = [
(lib.mkChangedOptionModule [ "qt" "useGtkTheme" ] [ "qt" "platformTheme" ]
(config:
if lib.getAttrFromPath [ "qt" "useGtkTheme" ] config then
"gtk"
else
null))
(lib.mkChangedOptionModule [ "qt" "useGtkTheme" ] [ "qt" "platformTheme" ] (
config: if lib.getAttrFromPath [ "qt" "useGtkTheme" ] config then "gtk" else null
))
];
options = {
qt = {
enable = lib.mkEnableOption "Qt 5 and 6 configuration";
platformTheme = let
newOption = {
name = lib.mkOption {
type = with lib.types; nullOr str;
default = null;
example = "adwaita";
relatedPackages = [
"qgnomeplatform"
"qgnomeplatform-qt6"
"qadwaitadecorations"
"qadwaitadecorations-qt6"
[ "libsForQt5" "plasma-integration" ]
[ "libsForQt5" "qt5ct" ]
[ "libsForQt5" "qtstyleplugins" ]
[ "libsForQt5" "systemsettings" ]
[ "kdePackages" "plasma-integration" ]
[ "kdePackages" "systemsettings" ]
[ "lxqt" "lxqt-config" ]
[ "lxqt" "lxqt-qtplugin" ]
[ "qt6Packages" "qt6ct" ]
[ "qt6Packages" "qt6gtk2" ]
];
description = ''
Platform theme to use for Qt applications.
platformTheme =
let
newOption = {
name = lib.mkOption {
type = with lib.types; nullOr str;
default = null;
example = "adwaita";
relatedPackages = [
"qgnomeplatform"
"qgnomeplatform-qt6"
"qadwaitadecorations"
"qadwaitadecorations-qt6"
[
"libsForQt5"
"plasma-integration"
]
[
"libsForQt5"
"qt5ct"
]
[
"libsForQt5"
"qtstyleplugins"
]
[
"libsForQt5"
"systemsettings"
]
[
"kdePackages"
"plasma-integration"
]
[
"kdePackages"
"systemsettings"
]
[
"lxqt"
"lxqt-config"
]
[
"lxqt"
"lxqt-qtplugin"
]
[
"qt6Packages"
"qt6ct"
]
[
"qt6Packages"
"qt6gtk2"
]
];
description = ''
Platform theme to use for Qt applications.
Some examples are
Some examples are
`gtk`
: Use GTK theme with
[`qtstyleplugins`](https://github.com/qt/qtstyleplugins)
`gtk`
: Use GTK theme with
[`qtstyleplugins`](https://github.com/qt/qtstyleplugins)
`gtk3`
: Use [GTK3 integration](https://github.com/qt/qtbase/tree/dev/src/plugins/platformthemes/gtk3)
for file picker dialogs, font and theme configuration
`gtk3`
: Use [GTK3 integration](https://github.com/qt/qtbase/tree/dev/src/plugins/platformthemes/gtk3)
for file picker dialogs, font and theme configuration
`adwaita`
: Use Adwaita theme with
[`qadwaitadecorations`](https://github.com/FedoraQt/QAdwaitaDecorations)
`adwaita`
: Use Adwaita theme with
[`qadwaitadecorations`](https://github.com/FedoraQt/QAdwaitaDecorations)
`gnome` (deprecated)
: Use GNOME theme with
[`qgnomeplatform`](https://github.com/FedoraQt/QGnomePlatform).
Is no longer maintained so prefer `adwaita`.
`gnome` (deprecated)
: Use GNOME theme with
[`qgnomeplatform`](https://github.com/FedoraQt/QGnomePlatform).
Is no longer maintained so prefer `adwaita`.
`lxqt`
: Use LXQt theme style set using the
[`lxqt-config-appearance`](https://github.com/lxqt/lxqt-config)
application
`lxqt`
: Use LXQt theme style set using the
[`lxqt-config-appearance`](https://github.com/lxqt/lxqt-config)
application
`qtct`
: Use Qt style set using
[`qt5ct`](https://github.com/desktop-app/qt5ct)
and [`qt6ct`](https://github.com/trialuser02/qt6ct)
applications
`qtct`
: Use Qt style set using
[`qt5ct`](https://github.com/desktop-app/qt5ct)
and [`qt6ct`](https://github.com/trialuser02/qt6ct)
applications
`kde`
: Use Qt settings from Plasma 5
`kde`
: Use Qt settings from Plasma 5
`kde6`
: Use Qt settings from Plasma 6
'';
};
package = lib.mkOption {
type = with lib.types; nullOr (either package (listOf package));
default = null;
example =
lib.literalExpression "[pkgs.adwaita-qt pkgs.adwaita-qt6]";
description = ''
Theme package to be used in Qt5/Qt6 applications.
Auto-detected from {option}`qt.platformTheme.name` if possible.
See its documentation for available options.
'';
`kde6`
: Use Qt settings from Plasma 6
'';
};
package = lib.mkOption {
type = with lib.types; nullOr (either package (listOf package));
default = null;
example = lib.literalExpression "[pkgs.adwaita-qt pkgs.adwaita-qt6]";
description = ''
Theme package to be used in Qt5/Qt6 applications.
Auto-detected from {option}`qt.platformTheme.name` if possible.
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 = {
name = lib.mkOption {
type = with lib.types; nullOr str;
@ -158,11 +237,26 @@ in {
relatedPackages = [
"adwaita-qt"
"adwaita-qt6"
[ "libsForQt5" "breeze-qt5" ]
[ "libsForQt5" "qtstyleplugin-kvantum" ]
[ "libsForQt5" "qtstyleplugins" ]
[ "qt6Packages" "qt6gtk2" ]
[ "qt6Packages" "qtstyleplugin-kvantum" ]
[
"libsForQt5"
"breeze-qt5"
]
[
"libsForQt5"
"qtstyleplugin-kvantum"
]
[
"libsForQt5"
"qtstyleplugins"
]
[
"qt6Packages"
"qt6gtk2"
]
[
"qt6Packages"
"qtstyleplugin-kvantum"
]
];
description = ''
Style to use for Qt5/Qt6 applications. Case-insensitive.
@ -201,80 +295,103 @@ in {
};
};
config = let
platformTheme = if (builtins.isString cfg.platformTheme) then {
option = "qt.platformTheme";
name = cfg.platformTheme;
package = null;
} else if cfg.platformTheme == null then {
option = null;
name = null;
package = null;
} else {
option = "qt.platformTheme.name";
name = cfg.platformTheme.name;
package = cfg.platformTheme.package;
config =
let
platformTheme =
if (builtins.isString cfg.platformTheme) then
{
option = "qt.platformTheme";
name = cfg.platformTheme;
package = null;
}
else if cfg.platformTheme == null then
{
option = null;
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" ];
};
}

View file

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

View file

@ -1,36 +1,47 @@
{ config, name, extendModules, lib, ... }:
{
config,
name,
extendModules,
lib,
...
}:
{
imports =
[ (lib.mkRenamedOptionModule [ "specialization" ] [ "specialisation" ]) ];
imports = [ (lib.mkRenamedOptionModule [ "specialization" ] [ "specialisation" ]) ];
options.specialisation = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule {
options = {
configuration = lib.mkOption {
type = let
extended = extendModules {
modules = [{
# Prevent infinite recursion
specialisation = lib.mkOverride 0 { };
type = lib.types.attrsOf (
lib.types.submodule {
options = {
configuration = lib.mkOption {
type =
let
extended = extendModules {
modules = [
{
# Prevent infinite recursion
specialisation = lib.mkOverride 0 { };
# If used inside the NixOS/nix-darwin module, we get conflicting definitions
# of `name` inside the specialisation: one is the user name coming from the
# NixOS module definition and the other is `configuration`, the name of this
# option. Thus we need to explicitly wire the former into the module arguments.
# See discussion at https://github.com/nix-community/home-manager/issues/3716
_module.args.name = lib.mkForce name;
}];
};
in extended.type;
default = { };
visible = "shallow";
description = ''
Arbitrary Home Manager configuration settings.
'';
# If used inside the NixOS/nix-darwin module, we get conflicting definitions
# of `name` inside the specialisation: one is the user name coming from the
# NixOS module definition and the other is `configuration`, the name of this
# option. Thus we need to explicitly wire the former into the module arguments.
# See discussion at https://github.com/nix-community/home-manager/issues/3716
_module.args.name = lib.mkForce name;
}
];
};
in
extended.type;
default = { };
visible = "shallow";
description = ''
Arbitrary Home Manager configuration settings.
'';
};
};
};
});
}
);
default = { };
description = ''
A set of named specialized configurations. These can be used to extend
@ -71,18 +82,21 @@
config = lib.mkIf (config.specialisation != { }) {
assertions = map (n: {
assertion = !lib.hasInfix "/" n;
message =
"<name> in specialisation.<name> cannot contain a forward slash.";
message = "<name> in specialisation.<name> cannot contain a forward slash.";
}) (lib.attrNames config.specialisation);
home.extraBuilderCommands = let
link = n: v:
let pkg = v.configuration.home.activationPackage;
in "ln -s ${pkg} $out/specialisation/${lib.escapeShellArg n}";
in ''
mkdir $out/specialisation
${lib.concatStringsSep "\n"
(lib.mapAttrsToList link config.specialisation)}
'';
home.extraBuilderCommands =
let
link =
n: v:
let
pkg = v.configuration.home.activationPackage;
in
"ln -s ${pkg} $out/specialisation/${lib.escapeShellArg n}";
in
''
mkdir $out/specialisation
${lib.concatStringsSep "\n" (lib.mapAttrsToList link config.specialisation)}
'';
};
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,14 +1,26 @@
{ config, pkgs, lib, ... }:
{
config,
pkgs,
lib,
...
}:
let
inherit (lib) mkIf mkMerge mkOption optional types;
inherit (lib)
mkIf
mkMerge
mkOption
optional
types
;
associationOptions = with types;
attrsOf (coercedTo (either (listOf str) str)
(x: lib.concatStringsSep ";" (lib.toList x)) str);
associationOptions =
with types;
attrsOf (coercedTo (either (listOf str) str) (x: lib.concatStringsSep ";" (lib.toList x)) str);
in {
in
{
meta.maintainers = [ lib.maintainers.misterio77 ];
options.xdg.portal = {
@ -63,12 +75,22 @@ in {
type = types.attrsOf associationOptions;
default = { };
example = {
x-cinnamon = { default = [ "xapp" "gtk" ]; };
x-cinnamon = {
default = [
"xapp"
"gtk"
];
};
pantheon = {
default = [ "pantheon" "gtk" ];
default = [
"pantheon"
"gtk"
];
"org.freedesktop.impl.portal.Secret" = [ "gnome-keyring" ];
};
common = { default = [ "gtk" ]; };
common = {
default = [ "gtk" ];
};
};
description = ''
Sets which portal backend should be used to provide the implementation
@ -97,51 +119,53 @@ in {
};
};
config = let
cfg = config.xdg.portal;
packages = [ pkgs.xdg-desktop-portal ] ++ cfg.extraPortals;
portalsDir =
"${config.home.profileDirectory}/share/xdg-desktop-portal/portals";
in mkIf cfg.enable {
warnings = optional (cfg.configPackages == [ ] && cfg.config == { }) ''
xdg-desktop-portal 1.17 reworked how portal implementations are loaded, you
should either set `xdg.portal.config` or `xdg.portal.configPackages`
to specify which portal backend to use for the requested interface.
config =
let
cfg = config.xdg.portal;
packages = [ pkgs.xdg-desktop-portal ] ++ cfg.extraPortals;
portalsDir = "${config.home.profileDirectory}/share/xdg-desktop-portal/portals";
in
mkIf cfg.enable {
warnings = optional (cfg.configPackages == [ ] && cfg.config == { }) ''
xdg-desktop-portal 1.17 reworked how portal implementations are loaded, you
should either set `xdg.portal.config` or `xdg.portal.configPackages`
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
portal implementation found in lexicographical order, use the following:
If you simply want to keep the behaviour in < 1.17, which uses the first
portal implementation found in lexicographical order, use the following:
xdg.portal.config.common.default = "*";
'';
xdg.portal.config.common.default = "*";
'';
assertions = [
(lib.hm.assertions.assertPlatform "xdg.portal" pkgs lib.platforms.linux)
assertions = [
(lib.hm.assertions.assertPlatform "xdg.portal" pkgs lib.platforms.linux)
{
assertion = cfg.extraPortals != [ ];
message =
"Setting xdg.portal.enable to true requires a portal implementation in xdg.portal.extraPortals such as xdg-desktop-portal-gtk or xdg-desktop-portal-kde.";
}
];
home = {
packages = packages ++ cfg.configPackages;
sessionVariables = mkMerge [
(mkIf cfg.xdgOpenUsePortal { NIXOS_XDG_OPEN_USE_PORTAL = "1"; })
{ NIX_XDG_DESKTOP_PORTAL_DIR = portalsDir; }
{
assertion = cfg.extraPortals != [ ];
message = "Setting xdg.portal.enable to true requires a portal implementation in xdg.portal.extraPortals such as xdg-desktop-portal-gtk or xdg-desktop-portal-kde.";
}
];
};
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;
};
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:
lib.optionalAttrs (conf != { }) {
"xdg-desktop-portal/${lib.optionalString (desktop != "common") "${desktop}-"}portals.conf".text =
lib.generators.toINI { }
{ preferred = conf; };
}
) cfg.config;
};
}

View file

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

View file

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

View file

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

View file

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