diff --git a/modules/misc/news.nix b/modules/misc/news.nix index 655546ff3..410238792 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -1,9 +1,6 @@ { config, lib, options, pkgs, ... }: - with lib; - let - cfg = config.news; hostPlatform = pkgs.stdenv.hostPlatform; @@ -44,7 +41,6 @@ let config = { id = mkDefault (builtins.hashString "sha256" config.message); }; }); - in { meta.maintainers = [ maintainers.rycee ]; @@ -1724,6 +1720,20 @@ in { editor). ''; } + + { + time = "2024-09-20T07:00:11+00:00"; + condition = config.programs.kitty.theme != null; + message = '' + The option 'programs.kitty.theme' has been deprecated, please use + 'programs.kitty.themeFile' instead. + + The 'programs.kitty.themeFile' option expects the file name of a + theme from `kitty-themes`, without the `.conf` suffix. See + for a + list of themes. + ''; + } ]; }; } diff --git a/modules/programs/kitty.nix b/modules/programs/kitty.nix index 48ec13da4..e9594ec12 100644 --- a/modules/programs/kitty.nix +++ b/modules/programs/kitty.nix @@ -3,7 +3,6 @@ with lib; let - cfg = config.programs.kitty; eitherStrBoolInt = with types; either str (either bool int); @@ -57,6 +56,26 @@ let ''; }; in { + imports = [ + (mkChangedOptionModule [ "programs" "kitty" "theme" ] [ + "programs" + "kitty" + "themeFile" + ] (config: + let value = getAttrFromPath [ "programs" "kitty" "theme" ] config; + in if value != null then + (let + matching = filter (x: x.name == value) (builtins.fromJSON + (builtins.readFile + "${pkgs.kitty-themes}/share/kitty-themes/themes.json")); + in throwIf (length matching == 0) + "kitty-themes does not contain a theme named ${value}" + strings.removeSuffix ".conf" + (strings.removePrefix "themes/" (head matching).file)) + else + null)) + ]; + options.programs.kitty = { enable = mkEnableOption "Kitty terminal emulator"; @@ -100,16 +119,16 @@ in { ''; }; - theme = mkOption { + themeFile = mkOption { type = types.nullOr types.str; default = null; description = '' - Apply a Kitty color theme. This option takes the friendly name of - any theme given by the command {command}`kitty +kitten themes`. - See - for more details. + Apply a Kitty color theme. This option takes the file name of a theme + in `kitty-themes`, without the `.conf` suffix. See + for a + list of themes. ''; - example = "Space Gray Eighties"; + example = "SpaceGray_Eighties"; }; font = mkOption { @@ -146,11 +165,11 @@ in { type = types.str; default = "no-rc"; example = "no-cursor"; - apply = (o: + apply = o: let modes = splitString " " o; filtered = filter (m: m != "no-rc") modes; - in concatStringsSep " " (concatLists [ [ "no-rc" ] filtered ])); + in concatStringsSep " " (concatLists [ [ "no-rc" ] filtered ]); description = '' Set the mode of the shell integration. This accepts the same options as the `shell_integration` option of Kitty. Note that @@ -184,24 +203,15 @@ in { text = '' # Generated by Home Manager. # See https://sw.kovidgoyal.net/kitty/conf.html - '' + concatStringsSep "\n" ([ - + '' + concatStringsSep "\n" [ (optionalString (cfg.font != null) '' font_family ${cfg.font.name} ${optionalString (cfg.font.size != null) "font_size ${toString cfg.font.size}"} '') - (optionalString (cfg.theme != null) '' - include ${pkgs.kitty-themes}/share/kitty-themes/${ - let - matching = filter (x: x.name == cfg.theme) (builtins.fromJSON - (builtins.readFile - "${pkgs.kitty-themes}/share/kitty-themes/themes.json")); - in throwIf (length matching == 0) - "kitty-themes does not contain a theme named ${cfg.theme}" - (head matching).file - } + (optionalString (cfg.themeFile != null) '' + include ${pkgs.kitty-themes}/share/kitty-themes/themes/${cfg.themeFile}.conf '') '' # Shell integration is sourced and configured manually @@ -211,13 +221,23 @@ in { (toKittyKeybindings cfg.keybindings) (toKittyEnv cfg.environment) cfg.extraConfig - ]); + ]; } // optionalAttrs pkgs.stdenv.hostPlatform.isLinux { onChange = '' ${pkgs.procps}/bin/pkill -USR1 -u $USER kitty || true ''; }; + home.activation.checkKittyTheme = mkIf (cfg.themeFile != null) (let + themePath = + "${pkgs.kitty-themes}/share/kitty-themes/themes/${cfg.themeFile}.conf"; + in hm.dag.entryBefore [ "writeBoundary" ] '' + if [[ ! -f "${themePath}" ]]; then + errorEcho "kitty-themes does not contain the theme file ${themePath}!" + exit 1 + fi + ''); + xdg.configFile."kitty/macos-launch-services-cmdline" = mkIf (cfg.darwinLaunchOptions != null && pkgs.stdenv.hostPlatform.isDarwin) { text = concatStringsSep " " cfg.darwinLaunchOptions; diff --git a/tests/integration/default.nix b/tests/integration/default.nix index c31030172..262f28faf 100644 --- a/tests/integration/default.nix +++ b/tests/integration/default.nix @@ -10,6 +10,7 @@ let }; tests = { + kitty = runTest ./standalone/kitty.nix; nixos-basics = runTest ./nixos/basics.nix; standalone-flake-basics = runTest ./standalone/flake-basics.nix; standalone-standard-basics = runTest ./standalone/standard-basics.nix; diff --git a/tests/integration/standalone/kitty-theme-bad-home.nix b/tests/integration/standalone/kitty-theme-bad-home.nix new file mode 100644 index 000000000..e4851701b --- /dev/null +++ b/tests/integration/standalone/kitty-theme-bad-home.nix @@ -0,0 +1,13 @@ +{ ... }: { + home.username = "alice"; + home.homeDirectory = "/home/alice"; + home.stateVersion = "24.05"; + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; + + programs.kitty = { + enable = true; + themeFile = "No Such Theme"; + }; +} diff --git a/tests/integration/standalone/kitty-theme-good-home.nix b/tests/integration/standalone/kitty-theme-good-home.nix new file mode 100644 index 000000000..f6085b1e1 --- /dev/null +++ b/tests/integration/standalone/kitty-theme-good-home.nix @@ -0,0 +1,14 @@ +{ ... }: { + home.username = "alice"; + home.homeDirectory = "/home/alice"; + + home.stateVersion = "24.05"; # Please read the comment before changing. + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; + + programs.kitty = { + enable = true; + themeFile = "SpaceGray_Eighties"; + }; +} diff --git a/tests/integration/standalone/kitty.nix b/tests/integration/standalone/kitty.nix new file mode 100644 index 000000000..8f89330cf --- /dev/null +++ b/tests/integration/standalone/kitty.nix @@ -0,0 +1,73 @@ +{ pkgs, ... }: { + name = "kitty-theme-path"; + meta.maintainers = [ pkgs.lib.maintainers.rycee ]; + + nodes.machine = { ... }: { + imports = [ "${pkgs.path}/nixos/modules/installer/cd-dvd/channel.nix" ]; + virtualisation.memorySize = 2048; + users.users.alice = { + isNormalUser = true; + description = "Alice Foobar"; + password = "foobar"; + uid = 1000; + }; + }; + + testScript = '' + start_all() + machine.wait_for_unit("network.target") + machine.wait_for_unit("multi-user.target") + + home_manager = "${../../..}" + + def login_as_alice(): + machine.wait_until_tty_matches("1", "login: ") + machine.send_chars("alice\n") + machine.wait_until_tty_matches("1", "Password: ") + machine.send_chars("foobar\n") + machine.wait_until_tty_matches("1", "alice\\@machine") + + def logout_alice(): + machine.send_chars("exit\n") + + def alice_cmd(cmd): + return f"su -l alice --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" + + def succeed_as_alice(cmd): + return machine.succeed(alice_cmd(cmd)) + + def fail_as_alice(cmd): + return machine.fail(alice_cmd(cmd)) + + # Create a persistent login so that Alice has a systemd session. + login_as_alice() + + # Set up a home-manager channel. + succeed_as_alice(" ; ".join([ + "mkdir -p /home/alice/.nix-defexpr/channels", + f"ln -s {home_manager} /home/alice/.nix-defexpr/channels/home-manager" + ])) + + succeed_as_alice("nix-shell \"\" -A install") + + with subtest("Switch to Bad Kitty"): + succeed_as_alice("cp ${ + ./kitty-theme-bad-home.nix + } /home/alice/.config/home-manager/home.nix") + + actual = fail_as_alice("home-manager switch") + expected = "kitty-themes does not contain the theme file" + assert expected in actual, \ + f"expected home-manager switch to contain {expected}, but got {actual}" + + with subtest("Switch to Good Kitty"): + succeed_as_alice("cp ${ + ./kitty-theme-good-home.nix + } /home/alice/.config/home-manager/home.nix") + + actual = succeed_as_alice("home-manager switch") + expected = "Activating checkKittyTheme" + assert expected in actual, \ + f"expected home-manager switch to contain {expected}, but got {actual}" + ''; +} diff --git a/tests/modules/programs/kitty/default.nix b/tests/modules/programs/kitty/default.nix index 694c43cd8..76016d516 100644 --- a/tests/modules/programs/kitty/default.nix +++ b/tests/modules/programs/kitty/default.nix @@ -1 +1,4 @@ -{ kitty-example-settings = ./example-settings.nix; } +{ + kitty-example-settings = ./example-settings.nix; + kitty-theme-to-themeFile = ./theme-to-themeFile.nix; +} diff --git a/tests/modules/programs/kitty/theme-to-themeFile.nix b/tests/modules/programs/kitty/theme-to-themeFile.nix new file mode 100644 index 000000000..84596bba9 --- /dev/null +++ b/tests/modules/programs/kitty/theme-to-themeFile.nix @@ -0,0 +1,24 @@ +{ config, lib, pkgs, options, ... }: { + config = { + programs.kitty = { + enable = true; + theme = "Space Gray Eighties"; + }; + + test.stubs.kitty = { }; + + test.asserts.warnings.enable = true; + test.asserts.warnings.expected = [ + ("The option `programs.kitty.theme' defined in ${ + lib.showFiles options.programs.kitty.theme.files + } has been changed to `programs.kitty.themeFile' that has a different" + + " type. Please read `programs.kitty.themeFile' documentation and" + + " update your configuration accordingly.") + ]; + + nmt.script = '' + assertFileExists home-files/.config/kitty/kitty.conf + assertFileRegex home-files/.config/kitty/kitty.conf "^include .*themes/SpaceGray_Eighties\.conf$" + ''; + }; +}