diff --git a/modules/misc/news/2025/11/2025-11-27_08-22-14.nix b/modules/misc/news/2025/11/2025-11-27_08-22-14.nix new file mode 100644 index 000000000..8a10b6426 --- /dev/null +++ b/modules/misc/news/2025/11/2025-11-27_08-22-14.nix @@ -0,0 +1,10 @@ +{ pkgs, ... }: +{ + time = "2025-11-27T07:22:14+00:00"; + condition = pkgs.stdenv.hostPlatform.isDarwin; + message = '' + A new module is available: 'programs.infat'. + Infat is a command line tool to set default openers + for file formats and url schemes on macOS. + ''; +} diff --git a/modules/programs/infat.nix b/modules/programs/infat.nix new file mode 100644 index 000000000..8ec05a677 --- /dev/null +++ b/modules/programs/infat.nix @@ -0,0 +1,81 @@ +{ + lib, + config, + pkgs, + ... +}: +let + cfg = config.programs.infat; + tomlFormat = pkgs.formats.toml { }; + + configDir = + if config.xdg.enable then + config.xdg.configHome + else + "${config.home.homeDirectory}/Library/Application Support"; + + configFile = "${configDir}/infat/config.toml"; +in +{ + meta.maintainers = with lib.maintainers; [ + mirkolenz + ]; + + options = { + programs.infat = { + enable = lib.mkEnableOption "infat"; + package = lib.mkPackageOption pkgs "infat" { nullable = true; }; + settings = lib.mkOption { + type = tomlFormat.type; + default = { }; + example = lib.literalExpression '' + { + extensions = { + md = "TextEdit"; + html = "Safari"; + pdf = "Preview"; + }; + schemes = { + mailto = "Mail"; + web = "Safari"; + }; + types = { + plain-text = "VSCode"; + }; + } + ''; + description = '' + Configuration written to + {file}`$XDG_CONFIG_HOME/infat/config.toml`. + ''; + }; + autoActivate = lib.mkEnableOption "auto-activate infat" // { + default = true; + example = false; + description = '' + Automatically activate infat on startup. + This is useful if you want to use infat as a + default application handler for certain file types. + If you don't want this, set this to false. + This option is only effective if `settings` is set. + ''; + }; + }; + }; + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "programs.infat" pkgs lib.platforms.darwin) + ]; + home = { + packages = lib.mkIf (cfg.package != null) [ cfg.package ]; + file.${configFile} = lib.mkIf (cfg.settings != { }) { + source = tomlFormat.generate "infat-settings.toml" cfg.settings; + }; + activation = lib.mkIf (cfg.settings != { } && cfg.package != null && cfg.autoActivate) { + infat = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + run ${lib.getExe cfg.package} --config "${configFile}" $VERBOSE_ARG + ''; + }; + }; + }; +} diff --git a/tests/modules/programs/infat/default.nix b/tests/modules/programs/infat/default.nix new file mode 100644 index 000000000..8fdd5ecc1 --- /dev/null +++ b/tests/modules/programs/infat/default.nix @@ -0,0 +1,6 @@ +{ lib, pkgs, ... }: + +lib.optionalAttrs pkgs.stdenv.hostPlatform.isDarwin { + infat-example-settings = ./example-settings.nix; + infat-no-settings = ./no-settings.nix; +} diff --git a/tests/modules/programs/infat/example-settings.nix b/tests/modules/programs/infat/example-settings.nix new file mode 100644 index 000000000..a9980d788 --- /dev/null +++ b/tests/modules/programs/infat/example-settings.nix @@ -0,0 +1,39 @@ +{ pkgs, ... }: + +{ + programs.infat = { + enable = true; + settings = { + extensions = { + md = "TextEdit"; + }; + schemes = { + web = "Safari"; + }; + types = { + plain-text = "VSCode"; + }; + }; + }; + + test.stubs.infat = { }; + + nmt.script = + let + expectedConfigPath = "home-files/.config/infat/config.toml"; + expectedConfigContent = pkgs.writeText "infat.config.expected" '' + [extensions] + md = "TextEdit" + + [schemes] + web = "Safari" + + [types] + plain-text = "VSCode" + ''; + in + '' + assertFileExists "${expectedConfigPath}" + assertFileContent "${expectedConfigPath}" "${expectedConfigContent}" + ''; +} diff --git a/tests/modules/programs/infat/no-settings.nix b/tests/modules/programs/infat/no-settings.nix new file mode 100644 index 000000000..fdb970a41 --- /dev/null +++ b/tests/modules/programs/infat/no-settings.nix @@ -0,0 +1,13 @@ +{ + programs.infat.enable = true; + + test.stubs.infat = { }; + + nmt.script = + let + expectedConfigPath = "home-files/.config/infat/config.toml"; + in + '' + assertPathNotExists "${expectedConfigPath}" + ''; +}