diff --git a/modules/misc/xdg-mime-apps.nix b/modules/misc/xdg-mime-apps.nix index b35eb1c6f..b28f488a8 100644 --- a/modules/misc/xdg-mime-apps.nix +++ b/modules/misc/xdg-mime-apps.nix @@ -75,6 +75,24 @@ in the list is attempted, and so on. ''; }; + + defaultApplicationPackages = mkOption { + type = types.listOf types.package; + default = [ ]; + example = [ + pkgs.eog + pkgs.evince + ]; + description = '' + Packages whose `.desktop` files will be used to establish default + mimetype associations. + + These associations are appended to the associations in + [](#opt-xdg.mimeApps.defaultApplications). If multiple packages + associate with the same mime type, then the priority among them is + determined by their order in the list. + ''; + }; }; config = lib.mkMerge [ @@ -106,8 +124,12 @@ in done done > "$out" ''; + + processAll = p: processLines (builtins.readFile (associations p)); + + warning = "The Home Manager `lib.xdg.mimeAssociations` function is deprecated, you can now instead use the option `xdg.mimeApps.defaultApplicationPackages` to achieve the same without import from derivation"; in - p: processLines (builtins.readFile (associations p)); + lib.warn warning processAll; } (lib.mkIf cfg.enable { @@ -118,15 +140,44 @@ in # Deprecated but still used by some applications. xdg.dataFile."applications/mimeapps.list".source = config.xdg.configFile."mimeapps.list".source; - xdg.configFile."mimeapps.list".text = + xdg.configFile."mimeapps.list".source = let joinValues = lib.mapAttrs (n: lib.concatStringsSep ";"); + + baseFile = (pkgs.formats.ini { }).generate "mimeapps.list" { + "Added Associations" = joinValues cfg.associations.added; + "Removed Associations" = joinValues cfg.associations.removed; + "Default Applications" = joinValues cfg.defaultApplications; + }; + + # With default application packages merged into the generated base file. + mergedFile = pkgs.runCommand "mimeapps.list" { ps = cfg.defaultApplicationPackages; } '' + export PATH=$PATH:${pkgs.crudini}/bin + + function mergeEntry() { + local mime="$1" + local name="$2" + local existing + + existing="$(crudini --get $out 'Default Applications' "$mime" 2>/dev/null || true)" + local value="$existing''${existing:+;}''$name" + crudini --inplace --set $out 'Default Applications' "$mime" "$value" + } + + install -m644 ${baseFile} $out + + for p in $ps ; do + for path in "$p"/share/applications/*.desktop ; do + name="''${path##*/}" + mimes=$(crudini --get "$path" 'Desktop Entry' MimeType 2>/dev/null || true) + for mime in ''${mimes//;/ }; do + mergeEntry "$mime" "$name" + done + done + done + ''; in - lib.generators.toINI { } { - "Added Associations" = joinValues cfg.associations.added; - "Removed Associations" = joinValues cfg.associations.removed; - "Default Applications" = joinValues cfg.defaultApplications; - }; + if cfg.defaultApplicationPackages == [ ] then baseFile else mergedFile; }) ]; } diff --git a/tests/default.nix b/tests/default.nix index 67563a1fa..79fc32103 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -50,6 +50,7 @@ let inner = self: super: { inherit (pkgs) coreutils + crudini jq desktop-file-utils diffutils diff --git a/tests/modules/misc/xdg/mime-apps-basics-expected.ini b/tests/modules/misc/xdg/mime-apps-basics-expected.ini index c27181eb5..a4bc44bcd 100644 --- a/tests/modules/misc/xdg/mime-apps-basics-expected.ini +++ b/tests/modules/misc/xdg/mime-apps-basics-expected.ini @@ -1,9 +1,10 @@ [Added Associations] -mimetype1=foo1.desktop;foo2.desktop;foo3.desktop -mimetype2=foo4.desktop +image/jpeg=foo4.desktop +image/png=foo1.desktop;foo2.desktop;foo3.desktop [Default Applications] -mimetype1=default1.desktop;default2.desktop +image/png=default1.desktop;default2.desktop;test.desktop +image/svg+xml = test.desktop [Removed Associations] -mimetype1=foo5.desktop +image/png=foo5.desktop diff --git a/tests/modules/misc/xdg/mime-apps-basics.nix b/tests/modules/misc/xdg/mime-apps-basics.nix index ac28182b8..edea2c388 100644 --- a/tests/modules/misc/xdg/mime-apps-basics.nix +++ b/tests/modules/misc/xdg/mime-apps-basics.nix @@ -1,33 +1,44 @@ +{ pkgs, ... }: + { - config = { - xdg.mimeApps = { - enable = true; - associations = { - added = { - "mimetype1" = [ - "foo1.desktop" - "foo2.desktop" - "foo3.desktop" - ]; - "mimetype2" = "foo4.desktop"; - }; - removed = { - mimetype1 = "foo5.desktop"; - }; - }; - defaultApplications = { - "mimetype1" = [ - "default1.desktop" - "default2.desktop" + xdg.mimeApps = { + enable = true; + associations = { + added = { + "image/png" = [ + "foo1.desktop" + "foo2.desktop" + "foo3.desktop" ]; + "image/jpeg" = "foo4.desktop"; + }; + removed = { + "image/png" = "foo5.desktop"; }; }; - - nmt.script = '' - assertFileExists home-files/.config/mimeapps.list - assertFileContent \ - home-files/.config/mimeapps.list \ - ${./mime-apps-basics-expected.ini} - ''; + defaultApplications = { + "image/png" = [ + "default1.desktop" + "default2.desktop" + ]; + }; + defaultApplicationPackages = [ + (pkgs.makeDesktopItem { + type = "Application"; + name = "test"; + desktopName = "Test"; + mimeTypes = [ + "image/png" + "image/svg+xml" + ]; + }) + ]; }; + + nmt.script = '' + assertFileExists home-files/.config/mimeapps.list + assertFileContent \ + home-files/.config/mimeapps.list \ + ${./mime-apps-basics-expected.ini} + ''; }