fontconfig: add RFC42-style config file settings
This commit is contained in:
parent
4441446672
commit
c8f0b8ed44
3 changed files with 178 additions and 86 deletions
|
|
@ -14,13 +14,15 @@ let
|
|||
|
||||
cfg = config.fonts.fontconfig;
|
||||
|
||||
xml = pkgs.formats.xml { };
|
||||
|
||||
globalConfig = config;
|
||||
fontConfigFileType = lib.types.submodule (
|
||||
let
|
||||
noteContentOptionsExclusivity = ''
|
||||
Note that {option}`source` will be derived from {option}`text` if it is set; with override
|
||||
priorities being preserved. As a consequence, exactly one of {option}`text`, and
|
||||
{option}`source` must be set with highest priority.
|
||||
Note that {option}`source` will be derived from {option}`settings` and {option}`text` if they are
|
||||
set; with override priorities being preserved. As a consequence, exactly
|
||||
one of {option}`settings`, {option}`text`, and {option}`source` must be set with highest priority.
|
||||
'';
|
||||
in
|
||||
{
|
||||
|
|
@ -80,6 +82,27 @@ let
|
|||
defaultText = ''"''${toString config.priority}-hm-''${config.label}.conf"'';
|
||||
type = lib.types.nonEmptyStr;
|
||||
};
|
||||
settings = lib.mkOption {
|
||||
inherit (xml) type;
|
||||
default = { };
|
||||
example = {
|
||||
description = "Enable antialiasing";
|
||||
match = {
|
||||
"@target" = "font";
|
||||
edit = {
|
||||
"@mode" = "assign";
|
||||
"@name" = "antialias";
|
||||
bool = "true";
|
||||
};
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
Structured attrs of settings in the format of `pkgs.format.xml {}`. The
|
||||
settings are implicitly wrapped inside the `<fontconfig>` tag, i.e. as
|
||||
`{ fontconfig = <settings>; }`.
|
||||
''
|
||||
+ noteContentOptionsExclusivity;
|
||||
};
|
||||
text = lib.mkOption {
|
||||
description = ''
|
||||
Verbatim contents of the config file.
|
||||
|
|
@ -119,9 +142,13 @@ let
|
|||
config.source =
|
||||
let
|
||||
fileName = lib.hm.strings.storeFileName "hm-fontconfig-${config.label}.xml";
|
||||
mkSettingsFile = settings: xml.generate fileName { fontconfig = settings; };
|
||||
mkTextFile = pkgs.writeText fileName;
|
||||
in
|
||||
lib.mkIf (config.text != null) (lib.mkDerivedConfig options.text mkTextFile);
|
||||
lib.mkMerge [
|
||||
(lib.mkIf (config.settings != { }) (lib.mkDerivedConfig options.settings mkSettingsFile))
|
||||
(lib.mkIf (config.text != null) (lib.mkDerivedConfig options.text mkTextFile))
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -322,93 +349,88 @@ in
|
|||
fi
|
||||
'';
|
||||
|
||||
fonts.fontconfig.configFile =
|
||||
let
|
||||
xml = pkgs.formats.xml { };
|
||||
mkFontconfigConf = name: conf: xml.generate name { fontconfig = conf; };
|
||||
in
|
||||
{
|
||||
fonts =
|
||||
let
|
||||
mkInclude = path: {
|
||||
"@ignore_missing" = "yes";
|
||||
"#text" = path;
|
||||
fonts.fontconfig.configFile = {
|
||||
fonts =
|
||||
let
|
||||
mkInclude = path: {
|
||||
"@ignore_missing" = "yes";
|
||||
"#text" = path;
|
||||
};
|
||||
in
|
||||
{
|
||||
enable = true;
|
||||
priority = 10;
|
||||
settings = {
|
||||
description = "Add fonts in the Nix user profile";
|
||||
include = map mkInclude [
|
||||
"${config.home.path}/etc/fonts/conf.d"
|
||||
"${config.home.path}/etc/fonts/fonts.conf"
|
||||
];
|
||||
dir = [
|
||||
"${config.home.path}/lib/X11/fonts"
|
||||
"${config.home.path}/share/fonts"
|
||||
"${config.home.profileDirectory}/lib/X11/fonts"
|
||||
"${config.home.profileDirectory}/share/fonts"
|
||||
];
|
||||
cachedir = "${config.home.path}/lib/fontconfig/cache";
|
||||
};
|
||||
};
|
||||
rendering =
|
||||
let
|
||||
toXmlValue =
|
||||
value:
|
||||
if lib.isBool value then
|
||||
{ bool = lib.boolToString value; }
|
||||
else if lib.isString value then
|
||||
{ const = value; }
|
||||
else
|
||||
throw "expected bool or string but got ${lib.typeOf value}: ${toString value}";
|
||||
assign =
|
||||
name: value:
|
||||
toXmlValue value
|
||||
// {
|
||||
"@mode" = "assign";
|
||||
"@name" = name;
|
||||
};
|
||||
in
|
||||
{
|
||||
enable = true;
|
||||
priority = 10;
|
||||
source = mkFontconfigConf "fonts" {
|
||||
description = "Add fonts in the Nix user profile";
|
||||
include = map mkInclude [
|
||||
"${config.home.path}/etc/fonts/conf.d"
|
||||
"${config.home.path}/etc/fonts/fonts.conf"
|
||||
];
|
||||
dir = [
|
||||
"${config.home.path}/lib/X11/fonts"
|
||||
"${config.home.path}/share/fonts"
|
||||
"${config.home.profileDirectory}/lib/X11/fonts"
|
||||
"${config.home.profileDirectory}/share/fonts"
|
||||
];
|
||||
cachedir = "${config.home.path}/lib/fontconfig/cache";
|
||||
content =
|
||||
lib.optional (cfg.antialiasing != null) (assign "antialias" cfg.antialiasing)
|
||||
++ lib.optionals (cfg.hinting != null) [
|
||||
(assign "hinting" true)
|
||||
(assign "hintstyle" ("hint" + cfg.hinting))
|
||||
]
|
||||
++ lib.optional (cfg.subpixelRendering != null) (
|
||||
assign "rgba" (lib.replaceStrings [ "ertical-" ] [ "" ] cfg.subpixelRendering)
|
||||
);
|
||||
in
|
||||
{
|
||||
enable = lib.length content > 0;
|
||||
priority = 10;
|
||||
settings = {
|
||||
description = "Set the rendering mode";
|
||||
match = {
|
||||
"@target" = "font";
|
||||
edit = content;
|
||||
};
|
||||
};
|
||||
rendering =
|
||||
let
|
||||
toXmlValue =
|
||||
value:
|
||||
if lib.isBool value then
|
||||
{ bool = lib.boolToString value; }
|
||||
else if lib.isString value then
|
||||
{ const = value; }
|
||||
else
|
||||
throw "expected bool or string but got ${lib.typeOf value}: ${toString value}";
|
||||
assign =
|
||||
name: value:
|
||||
toXmlValue value
|
||||
// {
|
||||
"@mode" = "assign";
|
||||
"@name" = name;
|
||||
};
|
||||
content =
|
||||
lib.optional (cfg.antialiasing != null) (assign "antialias" cfg.antialiasing)
|
||||
++ lib.optionals (cfg.hinting != null) [
|
||||
(assign "hinting" true)
|
||||
(assign "hintstyle" ("hint" + cfg.hinting))
|
||||
]
|
||||
++ lib.optional (cfg.subpixelRendering != null) (
|
||||
assign "rgba" (lib.replaceStrings [ "ertical-" ] [ "" ] cfg.subpixelRendering)
|
||||
);
|
||||
in
|
||||
{
|
||||
enable = lib.length content > 0;
|
||||
priority = 10;
|
||||
source = mkFontconfigConf "rendering" {
|
||||
description = "Set the rendering mode";
|
||||
match = {
|
||||
"@target" = "font";
|
||||
edit = content;
|
||||
};
|
||||
};
|
||||
};
|
||||
default-fonts =
|
||||
let
|
||||
filterNonEmpty = lib.filterAttrs (_: fonts: fonts != [ ]);
|
||||
mkAlias = name: fonts: {
|
||||
"@binding" = "same";
|
||||
family = if name == "sansSerif" then "sans-serif" else name;
|
||||
prefer.family = fonts;
|
||||
};
|
||||
default-fonts =
|
||||
let
|
||||
filterNonEmpty = lib.filterAttrs (_: fonts: fonts != [ ]);
|
||||
mkAlias = name: fonts: {
|
||||
"@binding" = "same";
|
||||
family = if name == "sansSerif" then "sans-serif" else name;
|
||||
prefer.family = fonts;
|
||||
};
|
||||
in
|
||||
{
|
||||
enable = true;
|
||||
priority = 52;
|
||||
source = mkFontconfigConf "default-fonts" {
|
||||
description = "Set default fonts";
|
||||
alias = lib.mapAttrsToList mkAlias (filterNonEmpty cfg.defaultFonts);
|
||||
};
|
||||
in
|
||||
{
|
||||
enable = true;
|
||||
priority = 52;
|
||||
settings = {
|
||||
description = "Set default fonts";
|
||||
alias = lib.mapAttrsToList mkAlias (filterNonEmpty cfg.defaultFonts);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
xdg.configFile = lib.mapAttrs' (
|
||||
_name: config:
|
||||
|
|
|
|||
18
modules/misc/news/2026/04/2026-04-26_14-42-03.nix
Normal file
18
modules/misc/news/2026/04/2026-04-26_14-42-03.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{ config, lib, ... }:
|
||||
{
|
||||
time = "2026-04-26T12:42:03+00:00";
|
||||
condition =
|
||||
let
|
||||
extraConfigFiles = lib.removeAttrs config.fonts.fontconfig.configFile [
|
||||
"fonts"
|
||||
"rendering"
|
||||
"default-fonts"
|
||||
];
|
||||
in
|
||||
config.fonts.fontconfig.enable && extraConfigFiles != { };
|
||||
message = ''
|
||||
There is a new `fonts.fontconfig.configFile.<name>.settings` option to
|
||||
define Fontconfig configuration files via a structured attrs in the
|
||||
format of `pkgs.formats.xml {}`.
|
||||
'';
|
||||
}
|
||||
|
|
@ -2,6 +2,26 @@
|
|||
|
||||
let
|
||||
fcConfD = "home-files/.config/fontconfig/conf.d";
|
||||
sampleSettings = {
|
||||
a = [
|
||||
{
|
||||
"@attr" = "value";
|
||||
b = 1;
|
||||
}
|
||||
{ c = "string"; }
|
||||
];
|
||||
};
|
||||
sampleSettingsFile = builtins.toFile "sample-settings-config" ''
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<fontconfig>
|
||||
<a attr="value">
|
||||
<b>1</b>
|
||||
</a>
|
||||
<a>
|
||||
<c>string</c>
|
||||
</a>
|
||||
</fontconfig>
|
||||
'';
|
||||
sampleText = "hello world";
|
||||
sampleTextFile = builtins.toFile "sample-text-config" sampleText;
|
||||
sampleSource = builtins.toFile "fontconfig-source" ''
|
||||
|
|
@ -34,14 +54,31 @@ in
|
|||
target = "target";
|
||||
text = "";
|
||||
};
|
||||
settings.settings = sampleSettings;
|
||||
text.text = sampleText;
|
||||
source.source = sampleSource;
|
||||
|
||||
# Check that priorities are propagated
|
||||
settings-override-text = {
|
||||
settings = lib.mkForce sampleSettings;
|
||||
text = sampleText;
|
||||
};
|
||||
settings-override-source = {
|
||||
settings = lib.mkForce sampleSettings;
|
||||
source = sampleSource;
|
||||
};
|
||||
text-overrides-source = {
|
||||
text = lib.mkForce sampleText;
|
||||
source = sampleSource;
|
||||
};
|
||||
text-overrides-settings = {
|
||||
settings = sampleSettings;
|
||||
text = lib.mkForce sampleText;
|
||||
};
|
||||
source-overrides-settings = {
|
||||
settings = sampleSettings;
|
||||
source = lib.mkForce sampleSource;
|
||||
};
|
||||
source-overrides-text = {
|
||||
text = sampleText;
|
||||
source = lib.mkForce sampleSource;
|
||||
|
|
@ -60,15 +97,30 @@ in
|
|||
|
||||
assertFileExists ${fcConfD}/target
|
||||
|
||||
assertFileExists ${fcConfD}/90-hm-settings.conf
|
||||
assertFileContent ${fcConfD}/90-hm-settings.conf ${sampleSettingsFile}
|
||||
|
||||
assertFileExists ${fcConfD}/90-hm-text.conf
|
||||
assertFileContent ${fcConfD}/90-hm-text.conf ${sampleTextFile}
|
||||
|
||||
assertFileExists ${fcConfD}/90-hm-source.conf
|
||||
assertFileContent ${fcConfD}/90-hm-source.conf ${sampleSource}
|
||||
|
||||
assertFileExists ${fcConfD}/90-hm-settings-override-text.conf
|
||||
assertFileContent ${fcConfD}/90-hm-settings-override-text.conf ${sampleSettingsFile}
|
||||
|
||||
assertFileExists ${fcConfD}/90-hm-settings-override-source.conf
|
||||
assertFileContent ${fcConfD}/90-hm-settings-override-source.conf ${sampleSettingsFile}
|
||||
|
||||
assertFileExists ${fcConfD}/90-hm-text-overrides-source.conf
|
||||
assertFileContent ${fcConfD}/90-hm-text-overrides-source.conf ${sampleTextFile}
|
||||
|
||||
assertFileExists ${fcConfD}/90-hm-text-overrides-settings.conf
|
||||
assertFileContent ${fcConfD}/90-hm-text-overrides-settings.conf ${sampleTextFile}
|
||||
|
||||
assertFileExists ${fcConfD}/90-hm-source-overrides-settings.conf
|
||||
assertFileContent ${fcConfD}/90-hm-source-overrides-settings.conf ${sampleSource}
|
||||
|
||||
assertFileExists ${fcConfD}/90-hm-source-overrides-text.conf
|
||||
assertFileContent ${fcConfD}/90-hm-source-overrides-text.conf ${sampleSource}
|
||||
'';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue