chore: format and add meta module

This commit is contained in:
technofab 2025-09-15 11:28:58 +02:00
parent 223000e43c
commit 5fee6ef12a
No known key found for this signature in database
7 changed files with 238 additions and 8 deletions

View file

@ -1,5 +1,5 @@
{ {
outputs = i: { outputs = _i: {
lib = import ./.; lib = import ./.;
}; };
} }

View file

@ -2,5 +2,6 @@
imports = [ imports = [
./main.nix ./main.nix
./env.nix ./env.nix
./meta.nix
]; ];
} }

View file

@ -13,7 +13,7 @@
prefix, prefix,
... ...
} @ args: let } @ args: let
vals = filter (key: args.${key} != null && args.${key} != false) [ vals = filter (key: args.${key} != null && args.${key}) [
"eval" "eval"
"prefix" "prefix"
"unset" "unset"
@ -122,5 +122,14 @@ in {
}; };
enterShellCommands."env".text = concatStringsSep "\n" (map envToBash (builtins.attrValues config.env)); enterShellCommands."env".text = concatStringsSep "\n" (map envToBash (builtins.attrValues config.env));
# TODO: collect all env vars, then add them to the menu if they have a description and "visibile == true" # TODO: collect all env vars, then add them to the menu if they have a description and "visibile == true"
meta = {
sections."Environment Variables".color = "red";
entries."XDG_DATA_DIRS" = {
description = "Hello world";
section = "Environment Variables";
subEntries."Usage" = "hello world";
};
};
}; };
} }

View file

@ -124,8 +124,12 @@ in {
meta.mainProgram = "devshell-${config.name}"; meta.mainProgram = "devshell-${config.name}";
}; };
finalPackage = mkNakedShell { finalPackage = mkNakedShell {
name = config.name; inherit (config) name;
profile = config.shell.finalProfile; profile = config.shell.finalProfile;
passthru = {
metadata = config.meta.finalMetadata;
metadataJson = config.meta.finalJson;
};
}; };
}; };
} }

211
lib/modules/meta.nix Normal file
View file

@ -0,0 +1,211 @@
{
pkgs,
lib,
config,
...
}: let
inherit (lib) mkOption types optional mkIf concatMapStrings concatMapStringsSep toUpper splitString;
cfg = config.meta;
printSubtext = subtext:
# sh
''
printf " $FG_GRAY $RESET''${BOLD}${subtext.text}$RESET: ${subtext.desc}\n"
'';
printEntry = entry:
# sh
''
printf " $FG_${entry.color} %-*s$RESET $FG_GRAY%s$RESET\n" "${maxWidth}" "${entry.text}" "${entry.desc}"
${concatMapStrings printSubtext entry.subtexts}
'';
printGroup = group:
# sh
''
printf " $FG_WHITE$RESET$BG_WHITE$FG_BLACK %s $RESET$FG_WHITE$RESET\n" "${group.title}"
${concatMapStrings printEntry group.entries}
'';
calculateMaxWidth = groups: let
lengths = builtins.concatLists (builtins.map (
group:
builtins.map (entry: builtins.stringLength entry.text) group.entries
)
groups);
max = a: b:
if a > b
then a
else b;
maxLength =
if lengths == []
then 0
else builtins.foldl' max 0 lengths;
in
maxLength;
maxWidth = builtins.toString (calculateMaxWidth result);
printHeaderDescription = text:
concatMapStringsSep "\n" (line:
# sh
''
printf " $FG_BLUE$RESET $FG_WHITE%s$RESET\n" "${line}"
'') (splitString "\n" text);
menuPackage = pkgs.writeTextFile {
name = "menu";
destination = "/bin/menu";
executable = true;
text =
# sh
''
BOLD=$(tput bold)
RESET=$(tput sgr0)
FG_BLACK=$(tput setaf 0)
FG_RED=$(tput setaf 1)
FG_GREEN=$(tput setaf 2)
FG_YELLOW=$(tput setaf 3)
FG_BLUE=$(tput setaf 4)
FG_MAGENTA=$(tput setaf 5)
FG_CYAN=$(tput setaf 6)
FG_WHITE=$(tput setaf 7)
BG_WHITE=$(tput setab 7)
FG_GRAY=$(tput setaf 8)
printf " $FG_BLUE$RESET\n"
printf " $FG_BLUE$RESET $FG_YELLOW$BOLD%s$RESET\n" "${config.name}"
${printHeaderDescription cfg.description}
printf " $FG_BLUE$RESET\n"
printf "\n"
${concatMapStringsSep "printf '\n'\n" printGroup result}
'';
};
groupedEntries = builtins.foldl' (
acc: entryName: let
entry = cfg.entries.${entryName};
sectionName = entry.section;
section = cfg.sections.${sectionName} or {};
newEntry = {
text = entry.name;
desc = entry.description or "";
color = section.color or "BLUE";
subtexts = map (name: {
text = name;
desc = entry.subEntries.${name};
}) (builtins.attrNames entry.subEntries);
};
updatedSection =
if acc ? ${sectionName}
then acc.${sectionName} ++ [newEntry]
else [newEntry];
in
acc // {${sectionName} = updatedSection;}
) {} (builtins.attrNames cfg.entries);
result = builtins.map (sectionName: {
title = sectionName;
entries = groupedEntries.${sectionName} or [];
}) (builtins.attrNames groupedEntries);
in {
options.meta = {
enableMenu = mkOption {
type = types.bool;
default = true;
description = ''
Add a `menu` command which shows a nice overview/summary of the devshell.
'';
};
showMenu = mkOption {
type = types.enum ["always" "once" "never"];
default = "once";
description = ''
When to show the devshell menu. `once` uses a state file in `$REN_STATE`
to keep track of the first time.
'';
};
description = mkOption {
type = types.str;
default = "Welcome to the devshell.";
description = '''';
};
sections = mkOption {
type = types.attrsOf (types.submodule ({name, ...}: {
options = {
name = mkOption {
type = types.str;
default = name;
};
color = mkOption {
type = types.nullOr types.str;
default = "blue";
apply = toUpper;
};
};
}));
default = {
"general" = {};
};
};
entries = mkOption {
type = types.attrsOf (types.submodule ({name, ...}: {
options = {
name = mkOption {
type = types.str;
default = name;
};
section = mkOption {
type = types.str;
default = "general";
};
description = mkOption {
type = types.nullOr types.str;
default = null;
};
subEntries = mkOption {
type = types.attrs;
default = {};
};
};
}));
default = {};
};
finalMetadata = mkOption {
type = types.attrs;
internal = true;
};
finalJson = mkOption {
type = types.package;
internal = true;
};
};
config = {
meta = rec {
finalMetadata = {
inherit (config) name;
# inherit (cfg) sections entries;
sections = result;
};
finalJson = builtins.toFile "meta.json" (builtins.toJSON finalMetadata);
};
packages = optional cfg.enableMenu menuPackage;
# shows the menu when entering the devshell
enterShellCommands."menu".text = mkIf (cfg.enableMenu && cfg.showMenu != "never") (
if cfg.showMenu == "always"
then "menu"
else
# sh
''
if [[ ! -f "$REN_STATE/${config.name}_menu_shown" ]]; then
touch "$REN_STATE/${config.name}_menu_shown"
menu
fi
''
);
};
}

View file

@ -30,7 +30,7 @@ in
(derivation { (derivation {
inherit name; inherit name;
system = stdenv.hostPlatform.system; inherit (stdenv.hostPlatform) system;
# `nix develop` actually checks and uses builder. And it must be bash. # `nix develop` actually checks and uses builder. And it must be bash.
builder = bashPath; builder = bashPath;

View file

@ -13,10 +13,15 @@ in {
}; };
}) })
]; ];
env."HELLO".value = "world!"; meta = {
enterShellCommands.test = { enableMenu = true;
text = "echo Hello $HELLO"; showMenu = "always";
deps = ["env"]; entries = {
"World" = {
section = "Hello";
description = "meow";
};
};
}; };
}; };
} }