numtide / devshell

Per project developer environments
https://numtide.github.io/devshell/
MIT License
1.25k stars 89 forks source link

Simplify assigning categories to packages #215

Open lilyball opened 2 years ago

lilyball commented 2 years ago

Is your feature request related to a problem? Please describe.

Categorizing commands can be tedious because I need to repeat the category over and over. I'm writing this as Nix but this is probably annoying in TOML too. I'd also like to group my commands by category in the configuration and ensure I don't forget categories.

Describe the solution you'd like

Right now commands is just a list of submodules. I would like to suggest that it should be a coercedTo that takes an attrset of lists of submodules (a subset of commandOptions that skips the category option) and coerces to the current submodule type by setting the attr key as the category. This way I can write something like

{
  commands.interactive = [
    { package = pkgs.cargo-deny; }
    { package = pkgs.cargo-insta; }
  ];
  commands.build = [
    { package = pkgs.cmakeCurses; name = "cmake"; }
    { package = pkgs.pkg-config; name = "pkg-config"; }
  ];
}

The downside here is I can't mix the attrset version and the current list of submodules within the same module (in Nix I can use mkMerge if I want that, but I can't do that in TOML), and so if I want to have a command with no category I have to remember that the category is "general commands". Though you could also do something like have the empty string as a category name fall back to "general commands", so I can write the following

{
  commands."" = [ … ];
}

This is mostly just so that way if you change the category name of "general commands" then this would work.

Describe alternatives you've considered

An alternative that would work in Nix configurations is to have a lib function that applies categories to its children. This is the approach I've taken in my local config, where I have a function that's used like

{
  commands = lib.devshell.categorize "interactive" [
    { package = pkgs.cargo-deny; }
    { package = pkgs.cargo-insta; }
  ] + lib.devshell.categorize "build" [
    { package = pkgs.cmakeCurses; name = "cmake"; }
    { package = pkgs.pkg-config; name = "pkg-config"; }
  ];
}

This is reasonably usable, but is less discoverable and won't work in TOML.

Given that this approach is Nix-only, and that in Nix I can already use mkMerge with the first approach to mix the attrsets and uncategorized entries I prefer the first approach. It also better reflects the command structure.

lilyball commented 2 years ago

Also see #216 in which I request the ability to provide a package directly instead of a { package = pkgs.cargo-deny; } attrset. These two requests can be done together, such that I could write

{
  commands.interactive = with pkgs; [ cargo-deny cargo-insta ];
  commands.build = with pkgs; [
    { package = cmakeCurses; name = "cmake"; }
    { package = pkg-config; name = "pkg-config"; }
  ];
}
zimbatm commented 2 years ago

Sounds good! This would also make overriding the default set of commands in the general category easier.