Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
267 changes: 164 additions & 103 deletions modules/grub/nixos.nix
Original file line number Diff line number Diff line change
@@ -1,45 +1,40 @@
{
mkTarget,
pkgs,
config,
lib,
...
}:
let
cfg = config.stylix.targets.grub;
inherit (config.stylix) imageScalingMode fonts;
inherit (config.lib.stylix) mkEnableTarget mkEnableWallpaper pixel;
# Grub requires fonts to be converted to "PFF2 format"
# This function takes a font { name, package } and produces a .pf2 file
mkGrubFont =
font:
pkgs.runCommand "${font.package.name}.pf2"
{
FONTCONFIG_FILE = pkgs.makeFontsConf { fontDirectories = [ font.package ]; };
}
''
# Use fontconfig to select the correct .ttf or .otf file based on name
font=$(
${lib.getExe' pkgs.fontconfig "fc-match"} \
${lib.escapeShellArg font.name} \
--format=%{file}
)

# Convert to .pf2
${lib.getExe' pkgs.grub2 "grub-mkfont"} $font --output $out --size ${toString fonts.sizes.applications}
'';

image-scale =
if imageScalingMode == "fill" then
"crop"
else if imageScalingMode == "fit" then
"fitheight"
else if imageScalingMode == "center" then
"padding"
# Grub doesn't seem to support tile
else
"crop";
inherit (config.lib.stylix) mkEnableWallpaper pixel;
in
{
mkTarget {
options = {
useWallpaper = mkEnableWallpaper "GRUB" false;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider deprecating useWallpaper as in commit ce22070 ("treewide: deprecate manual targets.${target}.useWallpaper.enable options (#2084)").

For consistency, it might be worth introducing the breaking change of useWallpaper changing its default from false to true.

theme = {
main = lib.mkOption {
type = lib.types.str;
default = "";
internal = true;
};
progress_bar = lib.mkOption {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this Nix variable not be camelCase:

Suggested change
progress_bar = lib.mkOption {
progressBar = lib.mkOption {

type = lib.types.str;
default = "";
internal = true;
};
Comment on lines +20 to +24

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This option is seemingly never set.

boot_menu = lib.mkOption {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this Nix variable not be camelCase:

Suggested change
boot_menu = lib.mkOption {
bootMenu = lib.mkOption {

type = lib.types.str;
default = "";
internal = true;
};
Comment on lines +25 to +29

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This option is seemingly never set.

extraBuildScript = lib.mkOption {
type = lib.types.str;
default = "";
internal = true;
};
};
};

imports = [
(lib.mkRenamedOptionModuleWith {
from = [
Expand All @@ -57,77 +52,127 @@ in
];
})
];
options.stylix.targets.grub = {
enable = mkEnableTarget "GRUB" true;
useWallpaper = mkEnableWallpaper "GRUB" false;
};

config.boot.loader.grub =
with config.lib.stylix.colors.withHashtag;
lib.mkIf (config.stylix.enable && cfg.enable) {
backgroundColor = base00;
# Need to override the NixOS splash, this will match the background
splashImage = pixel "base00";

# This font will be used for the GRUB terminal
font = toString (mkGrubFont fonts.monospace);

# TODO: Include OS icons

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This vanished comment should probably be brought back.

theme =
pkgs.runCommand "stylix-grub"
{
themeTxt = ''
desktop-image: "background.png"
desktop-image-scale-method: "${image-scale}"
desktop-color: "${base00}"

title-text: ""

terminal-left: "10%"
terminal-top: "20%"
terminal-width: "80%"
terminal-height: "60%"

+ progress_bar {
left = 25%
top = 80%+20 # 20 pixels below boot menu
width = 50%
height = 30

id = "__timeout__"
show_text = true
font = "${fonts.sansSerif.name}"
text = "@TIMEOUT_NOTIFICATION_MIDDLE@"

border_color = "${base00}"
bg_color = "${base00}"
fg_color = "${base0B}"
text_color = "${base05}"
}
config = [
(
{ cfg }:
lib.mkIf
(
cfg.theme.main != ""
|| cfg.theme.progress_bar != ""
|| cfg.theme.boot_menu != ""
Comment on lines +61 to +63

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the purpose of this clever condition is to only declare the otherwise unconditional Stylix theme when something of value happens, should it not guard on everything, including cfg.theme.extraBuildScript:

Suggested change
cfg.theme.main != ""
|| cfg.theme.progress_bar != ""
|| cfg.theme.boot_menu != ""
cfg.theme.main != ""
|| cfg.theme.progress_bar != ""
|| cfg.theme.boot_menu != ""
|| cfg.theme.extraBuildScript != ""

)
Comment on lines +59 to +64

@trueNAHO trueNAHO Jun 6, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not move this lib.mkIf into the single theme declaration:

theme =
  lib.mkIf
  (
    /* ... */
  )
  (
    pkgs.runCommand "stylix-grub"
      {
        /* ... */
      }
      (
        /* ... */
      )
  );

{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

diff --git a/modules/grub/nixos.nix b/modules/grub/nixos.nix
index 93195cd7..65a1cf79 100644
--- a/modules/grub/nixos.nix
+++ b/modules/grub/nixos.nix
@@ -63,7 +63,6 @@ mkTarget {
           || cfg.theme.boot_menu != ""
         )
         {
-
           theme =
             pkgs.runCommand "stylix-grub"
               {

+ boot_menu {
left = 25%
top = 20%
width = 50%
height = 60%
menu_pixmap_style = "background_*.png"
theme =
pkgs.runCommand "stylix-grub"
{
passAsFile = [ "themeTxt" ];
themeTxt = ''

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, this looks better without explicitly concatenating strings:

diff --git a/modules/grub/nixos.nix b/modules/grub/nixos.nix
index 93195cd7..a32c783c 100644
--- a/modules/grub/nixos.nix
+++ b/modules/grub/nixos.nix
@@ -77,36 +77,38 @@ mkTarget {
                   terminal-height: "60%"
 
                   ${cfg.theme.main}
-                ''
-                + lib.optionalString (cfg.theme.progress_bar != "") ''
-                  + progress_bar {
-                    left = 25%
-                    top = 80%+20  # 20 pixels below boot menu
-                    width = 50%
-                    height = 30
 
-                    id = "__timeout__"
-                    show_text = true
-                    text = "@TIMEOUT_NOTIFICATION_MIDDLE@"
-                    ${cfg.theme.progress_bar}
-                  }
-                ''
-                + lib.optionalString (cfg.theme.boot_menu != "") ''
-                  + boot_menu {
-                    left = 25%
-                    top = 20%
-                    width = 50%
-                    height = 60%
-                    menu_pixmap_style = "background_*.png"
+                  ${lib.optionalString (cfg.theme.progress_bar != "") ''
+                    + progress_bar {
+                      left = 25%
+                      top = 80%+20  # 20 pixels below boot menu
+                      width = 50%
+                      height = 30
+
+                      id = "__timeout__"
+                      show_text = true
+                      text = "@TIMEOUT_NOTIFICATION_MIDDLE@"
+                      ${cfg.theme.progress_bar}
+                    }
+                  ''}
+
+                  ${lib.optionalString (cfg.theme.boot_menu != "") ''
+                    + boot_menu {
+                      left = 25%
+                      top = 20%
+                      width = 50%
+                      height = 60%
+                      menu_pixmap_style = "background_*.png"
 
-                    item_height = 40
-                    item_icon_space = 8
-                    item_spacing = 0
-                    item_padding = 0
+                      item_height = 40
+                      item_icon_space = 8
+                      item_spacing = 0
+                      item_padding = 0
 
-                    selected_item_pixmap_style = "selection_*.png"
-                    ${cfg.theme.boot_menu}
-                  }
+                      selected_item_pixmap_style = "selection_*.png"
+                      ${cfg.theme.boot_menu}
+                    }
+                  ''}
                 '';
               }
               (

title-text: ""

item_height = 40
item_icon_space = 8
item_spacing = 0
item_padding = 0
item_font = "${fonts.sansSerif.name}"
item_color = "${base05}"
terminal-left: "10%"
terminal-top: "20%"
terminal-width: "80%"
terminal-height: "60%"

selected_item_color = "${base01}"
selected_item_pixmap_style = "selection_*.png"
${cfg.theme.main}
''
+ lib.optionalString (cfg.theme.progress_bar != "") ''
+ progress_bar {
left = 25%
top = 80%+20 # 20 pixels below boot menu
width = 50%
height = 30

id = "__timeout__"
show_text = true
text = "@TIMEOUT_NOTIFICATION_MIDDLE@"
${cfg.theme.progress_bar}
}
''
+ lib.optionalString (cfg.theme.boot_menu != "") ''
+ boot_menu {
left = 25%
top = 20%
width = 50%
height = 60%
menu_pixmap_style = "background_*.png"

item_height = 40
item_icon_space = 8
item_spacing = 0
item_padding = 0

selected_item_pixmap_style = "selection_*.png"
${cfg.theme.boot_menu}
}
'';
}
(
''
mkdir $out
cp $themeTxtPath $out/theme.txt
''
+ cfg.theme.extraBuildScript
);
Comment on lines +112 to +118

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, this looks better without explicitly concatenating strings:

diff --git a/modules/grub/nixos.nix b/modules/grub/nixos.nix
index 93195cd7..d4047b66 100644
--- a/modules/grub/nixos.nix
+++ b/modules/grub/nixos.nix
@@ -109,13 +109,12 @@ mkTarget {
                   }
                 '';
               }
-              (
-                ''
-                  mkdir $out
-                  cp $themeTxtPath $out/theme.txt
-                ''
-                + cfg.theme.extraBuildScript
-              );
+              ''
+                mkdir $out
+                cp $themeTxtPath $out/theme.txt
+
+                ${cfg.theme.extraBuildScript}
+              '';
         }
     )
     (

}
)
(
{ fonts }:
let
# Grub requires fonts to be converted to "PFF2 format"
# This function takes a font { name, package } and produces a .pf2 file
mkGrubFont =
font:
pkgs.runCommand "${font.package.name}.pf2"
{
FONTCONFIG_FILE = pkgs.makeFontsConf { fontDirectories = [ font.package ]; };
}
''
# Use fontconfig to select the correct .ttf or .otf file based on name
font=$(
${lib.getExe' pkgs.fontconfig "fc-match"} \
${lib.escapeShellArg font.name} \
--format=%{file}
)

# Convert to .pf2
${lib.getExe' pkgs.grub2 "grub-mkfont"} $font --output $out --size ${toString fonts.sizes.applications}
'';
passAsFile = [ "themeTxt" ];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we really move this passAsFile declaration higher in this PR? I do not mind the current removal of some noisy comments, or should we do all of this in a follow-up cleanup PR?

}
''
mkdir $out
cp $themeTxtPath $out/theme.txt
in
{
boot.loader.grub.font = toString (mkGrubFont fonts.monospace);
stylix.targets.grub.theme.extraBuildScript =
"cp ${mkGrubFont fonts.sansSerif} $out/sans_serif.pf2";
}
)
(
{
cfg,
image,
imageScalingMode,
}:
let
image-scale =
if imageScalingMode == "fill" then
"crop"
else if imageScalingMode == "fit" then
"fitheight"
else if imageScalingMode == "center" then
"padding"
# Grub doesn't seem to support tile
else
"crop";
in
{
stylix.targets.grub.theme = {
main = ''
desktop-image: "background.png"
desktop-image-scale-method: "${image-scale}"
'';
extraBuildScript = ''


Comment on lines +175 to 176

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the noisy empty lines:

diff --git a/modules/grub/nixos.nix b/modules/grub/nixos.nix
index 93195cd7..7cd1d2e7 100644
--- a/modules/grub/nixos.nix
+++ b/modules/grub/nixos.nix
@@ -172,8 +172,6 @@ mkTarget {
             desktop-image-scale-method: "${image-scale}"
           '';
           extraBuildScript = ''
-
-
             ${
               if
                 cfg.useWallpaper

${
if
Expand All @@ -136,7 +181,7 @@ in
then
''
${lib.getExe' pkgs.imagemagick "convert"} \
${lib.escapeShellArg config.stylix.image} \
${lib.escapeShellArg image} \
"png32:$out/background.png"
''
else
Expand All @@ -145,8 +190,24 @@ in

cp ${pixel "base01"} $out/background_c.png
cp ${pixel "base0B"} $out/selection_c.png

cp ${mkGrubFont fonts.sansSerif} $out/sans_serif.pf2
'';
};
};
}
)
(
{ colors }:
{
stylix.targets.grub.theme = {
main = ''
Comment on lines +200 to +201

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick:

Suggested change
stylix.targets.grub.theme = {
main = ''
stylix.targets.grub.theme.main = ''

desktop-color: "${colors.withHashtag.base00}"
'';
};
Comment on lines +200 to +204

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the surrounding newlines are optional, this could be simplified as something like:

Suggested change
stylix.targets.grub.theme = {
main = ''
desktop-color: "${colors.withHashtag.base00}"
'';
};
stylix.targets.grub.theme.main =
''desktop-color: "${colors.withHashtag.base00}"'';


boot.loader.grub = {
backgroundColor = colors.withHashtag.base00;
splashImage = pixel "base00";
};
}
)
];
}
Loading