diff --git a/modules/misc/news/2026/10/2026-10-21_06-43-34.nix b/modules/misc/news/2026/10/2026-10-21_06-43-34.nix new file mode 100644 index 0000000000..5eef3f49d6 --- /dev/null +++ b/modules/misc/news/2026/10/2026-10-21_06-43-34.nix @@ -0,0 +1,11 @@ +{ config, ... }: +{ + time = "2026-10-21T06:43:34+00:00"; + condition = config.programs.fresh-editor.enable; + message = '' + Fresh now supports `programs.fresh-editor.mutableSettings` to load + declarative settings from `config_linux.json` or `config_macos.json`, + leaving `config.json` writable by Fresh. Declarative settings override + the same keys in the user file. The option is disabled by default. + ''; +} diff --git a/modules/programs/fresh-editor.nix b/modules/programs/fresh-editor.nix index 2fac3e0ea6..f6ee1e4ea9 100644 --- a/modules/programs/fresh-editor.nix +++ b/modules/programs/fresh-editor.nix @@ -16,12 +16,38 @@ let cfg = config.programs.fresh-editor; jsonFormat = pkgs.formats.json { }; + settingsFile = + if cfg.mutableSettings then + "config_${if pkgs.stdenv.hostPlatform.isDarwin then "macos" else "linux"}.json" + else + "config.json"; in { meta.maintainers = with lib.maintainers; [ drupol ]; options.programs.fresh-editor = { enable = mkEnableOption "fresh-editor"; package = mkPackageOption pkgs "fresh-editor" { nullable = true; }; + mutableSettings = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Whether to put declarative settings in Fresh's platform configuration + file, leaving {file}`fresh/config.json` writable by Fresh. Declarative + settings override the same keys in the user file. Project and session + settings take precedence over the declarative settings. + + The declarative file is + {file}`$XDG_CONFIG_HOME/fresh/config_linux.json` on Linux and + {file}`~/.config/fresh/config_macos.json` on macOS. Fresh ignores + {env}`XDG_CONFIG_HOME` on macOS. + + Before disabling this option while + {option}`programs.fresh-editor.settings` is non-empty, remove or back up + the Fresh-owned {file}`fresh/config.json`. Home Manager otherwise + treats it as a file collision. + ''; + }; extraPackages = mkOption { type = with types; listOf package; default = [ ]; @@ -78,7 +104,11 @@ in VISUAL = "fresh"; }; - xdg.configFile."fresh/config.json" = mkIf (cfg.settings != { }) { + xdg.configFile."fresh/${settingsFile}" = mkIf (cfg.settings != { }) { + # Fresh uses ~/.config on macOS even when XDG_CONFIG_HOME is set. + target = mkIf ( + cfg.mutableSettings && pkgs.stdenv.hostPlatform.isDarwin + ) "${config.home.homeDirectory}/.config/fresh/${settingsFile}"; source = jsonFormat.generate "config.json" cfg.settings; }; }; diff --git a/tests/darwinScrublist.nix b/tests/darwinScrublist.nix index b719b46ed1..21955c6ff0 100644 --- a/tests/darwinScrublist.nix +++ b/tests/darwinScrublist.nix @@ -61,6 +61,7 @@ let "feh" "flameshot" "freetube" + "fresh-editor" "fzf" "gallery-dl" "getconf" diff --git a/tests/modules/programs/fresh-editor/default.nix b/tests/modules/programs/fresh-editor/default.nix index 7bb239a326..7eb1d6e738 100644 --- a/tests/modules/programs/fresh-editor/default.nix +++ b/tests/modules/programs/fresh-editor/default.nix @@ -1,3 +1,8 @@ { fresh-editor = ./fresh-editor-settings.nix; + fresh-editor-mutable = import ./mutable-settings.nix "mutable"; + fresh-editor-mutable-custom-xdg = import ./mutable-settings.nix "custom-xdg"; + fresh-editor-mutable-disabled = import ./mutable-settings.nix "disabled"; + fresh-editor-mutable-empty = import ./mutable-settings.nix "empty"; + fresh-editor-immutable-empty = import ./mutable-settings.nix "immutable-empty"; } diff --git a/tests/modules/programs/fresh-editor/fresh-editor-settings.nix b/tests/modules/programs/fresh-editor/fresh-editor-settings.nix index be2dfb22c9..ae4322dc15 100644 --- a/tests/modules/programs/fresh-editor/fresh-editor-settings.nix +++ b/tests/modules/programs/fresh-editor/fresh-editor-settings.nix @@ -6,5 +6,7 @@ nmt.script = '' assertFileContent home-files/.config/fresh/config.json ${./config.json} + assertPathNotExists home-files/.config/fresh/config_linux.json + assertPathNotExists home-files/.config/fresh/config_macos.json ''; } diff --git a/tests/modules/programs/fresh-editor/mutable-settings.nix b/tests/modules/programs/fresh-editor/mutable-settings.nix new file mode 100644 index 0000000000..0e1afdb22f --- /dev/null +++ b/tests/modules/programs/fresh-editor/mutable-settings.nix @@ -0,0 +1,52 @@ +mode: + +{ + config, + lib, + pkgs, + ... +}: + +let + customXdg = mode == "custom-xdg"; + hasSettings = + !(lib.elem mode [ + "empty" + "immutable-empty" + ]); + configDir = + if customXdg && !pkgs.stdenv.hostPlatform.isDarwin then "config with spaces" else ".config"; + platformFile = + if pkgs.stdenv.hostPlatform.isDarwin then "config_macos.json" else "config_linux.json"; + otherPlatformFile = + if pkgs.stdenv.hostPlatform.isDarwin then "config_linux.json" else "config_macos.json"; +in +{ + xdg.configHome = lib.mkIf customXdg "${config.home.homeDirectory}/config with spaces"; + + programs.fresh-editor = { + enable = mode != "disabled"; + mutableSettings = mode != "immutable-empty"; + settings = lib.optionalAttrs hasSettings (builtins.fromJSON (builtins.readFile ./config.json)); + }; + + nmt.script = '' + assertPathNotExists "home-files/${configDir}/fresh/config.json" + assertPathNotExists "home-files/${configDir}/fresh/${otherPlatformFile}" + '' + + ( + if hasSettings && mode != "disabled" then + '' + assertFileContent "home-files/${configDir}/fresh/${platformFile}" ${./config.json} + '' + else + '' + assertPathNotExists "home-files/${configDir}/fresh/${platformFile}" + '' + ) + + lib.optionalString customXdg '' + assertPathNotExists "home-files/${ + if pkgs.stdenv.hostPlatform.isDarwin then "config with spaces" else ".config" + }/fresh" + ''; +}