From 20c44bebb77231117f78eb8ddeb678dbfddfe609 Mon Sep 17 00:00:00 2001 From: Christoph Urlacher Date: Tue, 8 Jul 2025 18:57:28 +0200 Subject: [PATCH] Modules/Mime: Add mime module --- system/modules/default.nix | 1 + system/modules/mime/default.nix | 82 ++++++++ system/modules/mime/options.nix | 326 ++++++++++++++++++++++++++++++++ 3 files changed, 409 insertions(+) create mode 100644 system/modules/mime/default.nix create mode 100644 system/modules/mime/options.nix diff --git a/system/modules/default.nix b/system/modules/default.nix index affbae48..4881ba62 100644 --- a/system/modules/default.nix +++ b/system/modules/default.nix @@ -1,6 +1,7 @@ {...}: { imports = [ ./polkit + ./mime ./network ]; } diff --git a/system/modules/mime/default.nix b/system/modules/mime/default.nix new file mode 100644 index 00000000..650abe0b --- /dev/null +++ b/system/modules/mime/default.nix @@ -0,0 +1,82 @@ +{ + config, + lib, + mylib, + ... +}: let + inherit (config.modules) mime; +in { + options.modules.mime = import ./options.nix {inherit lib mylib;}; + + config = lib.mkIf mime.enable { + xdg = { + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types + # Find .desktop files: fd ".*\.desktop" / | grep --color=auto -E neovide + mime = rec { + enable = true; + + defaultApplications = let + associations = { + ${mime.defaultTextEditor} = mime.textTypes; + ${mime.defaultFileBrowser} = ["inode/directory"]; + ${mime.defaultWebBrowser} = mime.webTypes; + ${mime.defaultPdfViewer} = ["application/pdf"]; + ${mime.defaultImageViewer} = mime.imageTypes; + ${mime.defaultAudioPlayer} = mime.audioTypes; + ${mime.defaultVideoPlayer} = mime.videoTypes; + }; + + # Applied to a single app and a single type + # Result: { "image/jpg" = ["imv.desktop"]; } + mkAssociation = app: type: {${type} = [app];}; + + # Applied to a single app and a list of types + # Result: { "image/jpg" = ["imv.desktop"]; "image/png" = ["imv.desktop"]; ... } + mkAssociations = app: types: + lib.mergeAttrsList + (builtins.map (mkAssociation app) types); + in + # Apply to a list of apps each with a list of types + lib.mergeAttrsList (lib.mapAttrsToList mkAssociations associations); + + addedAssociations = defaultApplications; + + removedAssociations = let + # Applied to a list of apps and a single type + removeAssociation = apps: type: {${type} = apps;}; + + # Applied to a list of apps and a list of types: + # For each type the list of apps should be removed + removeAssociations = apps: types: + lib.mergeAttrsList + (builtins.map (removeAssociation apps) types); + + # Only create if more than 0 apps are specified: (len from...Types) > 0 + mkIfExists = apps: types: + lib.optionalAttrs + (builtins.lessThan 0 (builtins.length apps)) + (removeAssociations apps types); + in + lib.mergeAttrsList [ + { + "application/pdf" = [ + "chromium-browser.desktop" + "com.google.Chrome.desktop" + "firefox.desktop" + ]; + "text/plain" = [ + "firefox.desktop" + "code.desktop" + ]; + } + + (mkIfExists mime.removedTextTypes mime.textTypes) + (mkIfExists mime.removedImageTypes mime.imageTypes) + (mkIfExists mime.removedAudioTypes mime.audioTypes) + (mkIfExists mime.removedVideoTypes mime.videoTypes) + (mkIfExists mime.removedWebTypes mime.webTypes) + ]; + }; + }; + }; +} diff --git a/system/modules/mime/options.nix b/system/modules/mime/options.nix new file mode 100644 index 00000000..e5b131ec --- /dev/null +++ b/system/modules/mime/options.nix @@ -0,0 +1,326 @@ +{ + lib, + mylib, + ... +}: { + enable = lib.mkEnableOption "TEMPLATE"; + + defaultTextEditor = lib.mkOption { + type = lib.types.str; + description = "Default application to open text files"; + example = '' + "neovide.desktop" + ''; + default = "neovide.desktop"; + }; + + defaultFileBrowser = lib.mkOption { + type = lib.types.str; + description = "Default application for file browsing"; + example = '' + "yazi.desktop" + ''; + default = "yazi.desktop"; + }; + + defaultWebBrowser = lib.mkOption { + type = lib.types.str; + description = "Default web browser"; + example = '' + "firefox.desktop" + ''; + default = "firefox.desktop"; + }; + + defaultPdfViewer = lib.mkOption { + type = lib.types.str; + description = "Default application to open PDF files"; + example = '' + "org.pwmt.zathura.desktop" + ''; + default = "org.pwmt.zathura.desktop"; + }; + + defaultImageViewer = lib.mkOption { + type = lib.types.str; + description = "Default application to open image files"; + example = '' + "imv-dir.desktop" + ''; + default = "imv-dir.desktop"; + }; + + defaultAudioPlayer = lib.mkOption { + type = lib.types.str; + description = "Default application to play audio files"; + example = '' + "vlc.desktop" + ''; + default = "vlc.desktop"; + }; + + defaultVideoPlayer = lib.mkOption { + type = lib.types.str; + description = "Default application to play video files"; + example = '' + "vlc.desktop" + ''; + default = "vlc.desktop"; + }; + + textTypes = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "Mime types that should be associated with a text editor"; + example = '' + [ + "text/css" + "text/csv" + "text/javascript" + "text/plain" + "text/xml" + "application/json" + "application/ld+json" + "application/x-sh" + "application/xml" + ] + ''; + default = [ + "text/css" + "text/csv" + "text/javascript" + "text/plain" + "text/xml" + "application/json" + "application/ld+json" + "application/x-sh" + "application/xml" + ]; + }; + + imageTypes = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "Mime types that should be associated with an image viewer"; + example = '' + [ + "image/apng" + "image/avif" + "image/bmp" + "image/gif" + "image/jpeg" + "image/png" + "image/svg+xml" + "image/tiff" + "image/webp" + ] + ''; + default = [ + "image/apng" + "image/avif" + "image/bmp" + "image/gif" + "image/jpeg" + "image/png" + "image/svg+xml" + "image/tiff" + "image/webp" + ]; + }; + + audioTypes = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "Mime types that should be associated with an audio player"; + example = '' + [ + "audio/aac" + "audio/flac" + "audio/mp4" + "audio/mpeg" + "audio/ogg" + "audio/opus" + "audio/wav" + "audio/webm" + "audio/3gpp" + "audio/3gpp2" + ] + ''; + default = [ + "audio/aac" + "audio/flac" + "audio/mp4" + "audio/mpeg" + "audio/ogg" + "audio/opus" + "audio/wav" + "audio/webm" + "audio/3gpp" + "audio/3gpp2" + ]; + }; + + videoTypes = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "Mime types that should be associated with a video player"; + example = '' + [ + "video/x-msvideo" + "video/mp4" + "video/mpeg" + "video/ogg" + "video/mp2t" + "video/webm" + "video/3gpp" + "video/3gpp2" + ] + ''; + default = [ + "video/x-msvideo" + "video/mp4" + "video/mpeg" + "video/ogg" + "video/mp2t" + "video/webm" + "video/3gpp" + "video/3gpp2" + ]; + }; + + webTypes = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "Mime types that should be associated with a web browser"; + example = '' + [ + "text/uri-list" + "text/x-uri" + "text/html" + "application/xhtml+xml" + "x-scheme-handler/https" + ] + ''; + default = [ + "text/uri-list" + "text/x-uri" + "text/html" + "application/xhtml+xml" + "x-scheme-handler/https" + ]; + }; + + removedTextTypes = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "Applications that shouldn't be used to open text files"; + example = '' + [ + "nvim.desktop" + ] + ''; + default = [ + "nvim.desktop" + ]; + }; + + removedImageTypes = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "Applications that shouldn't be used to view image files"; + example = '' + [ + "imv.desktop" + "chromium-browser.desktop" + "org.kde.krita.desktop" + "krita.desktop" + "krita_svg.desktop" + "krita_raw.desktop" + "krita_heif.desktop" + "krita_webp.desktop" + "krita_gif.desktop" + "krita_brush.desktop" + "krita_xcf.desktop" + "krita_jpeg.desktop" + "krita_spriter.desktop" + "krita_jxl.desktop" + "krita_ora.desktop" + "krita_csv.desktop" + "krita_tga.desktop" + "krita_psd.desktop" + "krita_png.desktop" + "krita_tiff.desktop" + "krita_exr.desktop" + "krita_qimageio.desktop" + "krita_pdf.desktop" + "krita_jp2.desktop" + "krita_heightmap.desktop" + "krita_kra.desktop" + "krita_krz.desktop" + ] + ''; + default = [ + "imv.desktop" + "chromium-browser.desktop" + "org.kde.krita.desktop" + "krita.desktop" + "krita_svg.desktop" + "krita_raw.desktop" + "krita_heif.desktop" + "krita_webp.desktop" + "krita_gif.desktop" + "krita_brush.desktop" + "krita_xcf.desktop" + "krita_jpeg.desktop" + "krita_spriter.desktop" + "krita_jxl.desktop" + "krita_ora.desktop" + "krita_csv.desktop" + "krita_tga.desktop" + "krita_psd.desktop" + "krita_png.desktop" + "krita_tiff.desktop" + "krita_exr.desktop" + "krita_qimageio.desktop" + "krita_pdf.desktop" + "krita_jp2.desktop" + "krita_heightmap.desktop" + "krita_kra.desktop" + "krita_krz.desktop" + ]; + }; + + removedAudioTypes = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "Applications that shouldn't be used to play audio files"; + example = '' + [ + "mpv.desktop" + ] + ''; + default = [ + "mpv.desktop" + ]; + }; + + removedVideoTypes = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "Applications that shouldn't be used to play video files"; + example = '' + [ + "mpv.desktop" + ] + ''; + default = [ + "mpv.desktop" + ]; + }; + + removedWebTypes = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "Web browsers that shouldn't be used for web types"; + example = '' + [ + "chromium-browser.desktop" + "com.google.Chrome.desktop" + ] + ''; + default = [ + "chromium-browser.desktop" + "com.google.Chrome.desktop" + ]; + }; +}