Files
home-manager/modules/programs/libreoffice.nix
EKHH b8350fcdf5 libreoffice: add module
LibreOffice is a comprehensive office productivity suite.
2026-09-01 21:50:53 -05:00

136 lines
4.9 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.libreoffice;
xcuConfig = rec {
filePath = "libreoffice/4/user/registrymodifications.xcu";
inherit (lib.types) attrsOf oneOf;
valueTypes = lib.attrValues {
inherit (lib.types)
bool
float
int
str
;
};
type = attrsOf (attrsOf (oneOf valueTypes));
# `lib.toString` yields an empty string for `false` and "1" for true by
# default; use `lib.boolToString` to return "true" and "false" directly.
toValue = x: if lib.isBool x then lib.boolToString x else lib.toString x;
};
ooSetup = rec {
nullFallback = fn: x: if (x == null) then null else fn x;
versionPath = "/org.openoffice.Setup/Product";
versionKey = "ooSetupLastVersion";
packageVersion = nullFallback (x: x.version or null) cfg.package;
matchedVersions = nullFallback (
# Expected output: [ "xx.xx" ]
lib.match "^([[:digit:]]+[.][[:digit:]]+)[.]?.*$"
) packageVersion;
generatedVersion = nullFallback (lib.head) matchedVersions;
hasExplicitVersion = lib.hasAttrByPath [ versionPath versionKey ] cfg.settings;
};
in
{
meta.maintainers = lib.attrValues {
inherit (lib.maintainers)
ekhh
;
};
options.programs.libreoffice = {
enable = lib.mkEnableOption "LibreOffice, a comprehensive office suite.";
package = lib.mkPackageOption pkgs "libreoffice" {
nullable = true;
example = "pkgs.libreoffice-qt";
};
settings = lib.mkOption {
inherit (xcuConfig) type;
default = { };
example = {
"/org.openoffice.Office.Common/Filter/PDF/Export" = {
PDFUACompliance = true;
SelectPdfVersion = 4;
};
};
description = ''
Configuration written to {file}`$XDG_CONFIG_HOME/${xcuConfig.filePath}`.
Available options are documented as tooltips in the `Expert
Configuration` dialog.
Warning: this will silently delete the existing configuration file,
regardless of whether it is a file or a link; please back up your
configuration entries before migrating.
'';
};
};
config = lib.mkIf cfg.enable {
assertions = [
(lib.hm.assertions.assertPlatform "programs.libreoffice" pkgs lib.platforms.linux)
{
assertion = cfg.settings == { } || ooSetup.hasExplicitVersion || ooSetup.generatedVersion != null;
message = "`\"${ooSetup.versionPath}\".${ooSetup.versionKey}` must be set in `programs.libreoffice.settings`.";
}
];
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
# `builtins.toXML` has various issues and may be deprecated in the future;
# see <https://github.com/NixOS/nix/issues/15745#issue-4334624253>.
xdg.configFile.libreoffice-configuration = lib.mkIf (cfg.settings != { }) {
/*
Overrides existing configuration entries; LibreOffice writes a
configuration file upon launch regardless of whether or not the user has
configured anything, so we cannot check for the presence of a
meaningful entry. But we warned the user already in the option
description, and one would have to redo all the configuration entries
anyway given the abundance of confusing and useless entries written by
default, so it should be okay.
*/
force = true;
text = ''
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated by Home Manager. -->
<oor:items xmlns:oor="http://openoffice.org/2001/registry" ''
+ ''xmlns:xs="http://www.w3.org/2001/XMLSchema" ''
+ ''xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">''
+ "\n"
+
lib.concatMapAttrsStringSep ""
(
path: attrs:
lib.concatMapAttrsStringSep "" (
name: value:
/*
IMPORTANT: apply `lib.escapeXML` on everything. The
`givenname` field, for instance, accepts a string input; if
not escaped, an ampersand in a company's name is alone
sufficient to invalidate the configuration file.
*/
''<item oor:path="${lib.escapeXML path}">''
+ ''<prop oor:name="${lib.escapeXML name}" oor:op="fuse">''
+ "<value>${lib.escapeXML (xcuConfig.toValue value)}</value>"
+ "</prop></item>\n"
) attrs
)
(
lib.recursiveUpdate (lib.optionalAttrs
(ooSetup.hasExplicitVersion == false && ooSetup.generatedVersion != null)
/*
This value records the last major version (xx.x) whereupon a
setup was run. The configuration will be ignored if it is
absent.
*/
(lib.setAttrByPath [ ooSetup.versionPath ooSetup.versionKey ] ooSetup.generatedVersion)
) cfg.settings
)
+ "</oor:items>\n";
target = xcuConfig.filePath;
};
};
}