nix-community / nixvim

Configure Neovim with Nix! [maintainers=@GaetanLepage, @traxys, @mattsturgeon, @khaneliman]
https://nix-community.github.io/nixvim
MIT License
1.79k stars 280 forks source link

Help Configuring NixVim Config Files Path #2477

Open RicSanOP opened 2 weeks ago

RicSanOP commented 2 weeks ago

I want to run multiple styles of neovim configuration simultaneously on my systems. With NixVim, all config files are by default simlinked into the ~/.config/nvim directory (as a side note I am using the home-manager nixvim module). I want to be able to redefine where the nixvim generated config files are placed. After some digging into the nixvim codebase I see 2 potential places where the config filepath could be configured:

1) this one is probably wrong but worth mentioning. nixvim has a path top-level option which I can't seem to exactly understand is used how.

2) looking at https://github.com/nix-community/nixvim/blob/main/wrappers/_shared.nix which is imported into each nixvim module wrapper (home-manager, nixos, darwin and standalone), I see a filesPrefix argument which is never really set but seems to solve the issue (it is set to nvim/ by default). However I don't see how I can set this variable myself.

Assuming the second option is the correct path to configuring where nixvim, could anyone suggest how I can easily set the variable? If the task requires building another complex wrapper or some internal mods to this codebase, I would be happy to work on a pull request if given a bit of guidance (I would say my nix level is intermediate as I have some experience now reading through nix codebases). This could also lead to further improvements of nixvim whereby one could create multiple configs that could be switched using the recent NVIM_APPNAME env variable. This could eventually lead to something like https://lazyman.dev (or an integration with it) which could help people explore neovim through multiple configs and distros.

Any help on this matter is very much appreciated.

MattSturgeon commented 2 weeks ago

We could (and probably should) add an option to allow configuring the files prefix, however you'll only be able to create one nixvim configuration if you're using a wrapper module to configure nixvim.

Maybe we should consider having a way to have multiple nixvim's configured per module eval... Perhaps we could setup something similar to our files option and have an attrset of name -> nixvimConfiguration.

All that said, this exact scenario is really what the "standalone" nixvim is intended to solve; although even that has some limitations.

The standalone build will not install the config files anywhere (other than the nix store, of course), and will instead tell the nvim wrapper script to use the -u flag with the init file when running neovim.

The main limitation for standalone builds is that we don't currently offer a sensible way to configure the nvim exe's name, meaning if you install multiple standalone nixvim they will conflict.

It would be possible to do something like this though, but we should probably consider better ways to solve all of these scenarios with new nixvim options.

.overrideAttrs {
  postInstall = ''
    mv $out/bin/nvim $out/bin/custom-nvim
  '';
}
GaetanLepage commented 2 weeks ago

Also, we have the wrapRc option that prevents the config file to end up in ~/.config. Not sure if this will work for your use case.

RicSanOP commented 2 weeks ago

@MattSturgeon @GaetanLepage thank you for your responses. Yes, overall I think it would be great for nixvim itself to have the ability to define multiple profiles and perhaps even manage multiple nvim installs.

In the most basic case, I just want to move the configs to another directory. Would it be possible to use an overrideAttr on the home manager module to move the config files from config/nvim to config/othername (similar to @MattSturgeon postInstall example)? If so, please advise where would a good place (in the flake or in home.nix) to define the override.

In the meantime I'm interested in helping define the option that would set the filePrefix wrapping on the wrapper scripts. Would appreciate if anyone can give some guidance on where to define the option appropriately and how to correctly pass it through the nix modules into the wrapper directory.

As for the bigger idea on letting nixvim create entire profiles, I would be interested in exploring further but it is not my personal priority as the other configs I want to run would be defined more standard neovim style, whilst leveraging nixvim extrapackages option.

RicSanOP commented 2 weeks ago

As for the wrapRc option, it technically solves the problem but introduces a new one which is getting access to the unwrapped nvim executable in order to run other configs. I wonder if the -u option has priority over NVIM_APPNAME. Will test when back on my computer.

RicSanOP commented 2 weeks ago

@MattSturgeon @GaetanLepage, I have worked on a home-manager module that allows for multiple concurrent profiles. I think I have done just about everything right on my end with regards to creating a multi profile option set for the module, which would reside at programs.nixvims. The only problem I seem to be having is that, for some odd reason, the .overrideAttrs invoking that overrides the postInstall derivation attribute does not seem to apply. Everytime I build a profile's nixvim derivation (which at the moment is a wrapped standalone), the nvim executable remains unchanged and is not renamed as I'd indicated in .overrideAttrs.postInstall. Here is the code of the module and an example of me testing it. It should be quite straightforward. @MattSturgeon @GaetanLepage please help me find the correct way to change the executable's filename because after that I could even build a pull request here or at home-manager. Go easy on me though, its my first time writing my own nix modules.

The module that is added to the home-manager modules list in the flake

{ self, inputs, config, pkgs, lib, nixvimFactory, ... }: # assume nixvimFactory alroady handles profile renaming and integration
let
  inherit (lib)
    mkEnableOption
    mkOption
    mkDefault
    mkIf
    types
    lists;
  cfg = config.programs.nixvims;
  mkNixvimProfile = profile: ((nixvimFactory {
      inherit pkgs;
      module = profile.module // { wrapRc = true; };
      extraSpecialArgs = profile.extraSpecialArgs;
    }).overrideAttrs {
      postInstall = ''
        mv $out/bin/nvim $out/bin/nvim${profile.exeName}
      ''; # in the future wrapRc can be toggled to move config files within ~/.config/nvim subdirectories
    });
  genNixvimDrvs = profiles: (lists.forEach profiles (p:
      mkNixvimProfile p
    ));
in
{
  options.programs.nixvims = {
    enable = mkEnableOption "enables nixvims";
    profiles = mkOption {
      type = types.listOf (types.submodule {
        options = {
          profileName = mkOption {
            type = types.str;
            default = "Default";
            description = "the profile's config path name if exported";
          };
          exeName = mkOption {
            type = types.str;
            default = "default";
            description = "the profile's executable name append nvim$exeName";
          };
          module = mkOption {
            type = types.attrs;
            default = { colorschemes.tokyonight.enable = true; };
            description = "the modules as they would be passed to the makeNixvimWithModule function";
          };
          extraSpecialArgs = mkOption {
            type = types.attrs;
            default = { };
            description = "the extraSpecialArgs as they would be passed to the makeNixvimWithModule function";
          };
        };
      });
    };
    default = [ ];
    description = "a list of profile attribute sets";
  };

  config = mkIf cfg.enable {
    home.packages = [
      #output of nixvimFactory should go here (start with one then do a map on profiles
      pkgs.hello #placeholder
    ] ++ (genNixvimDrvs cfg.profiles);
  };
}

An example home config using the new nixvims module

{ self, inputs, config, pkgs, lib, nixvimFactory, ... }:

{
  programs.nixvims = {
    enable = true;
    profiles = [
      {
        profileName = "Test";
        exeName = "test";
        module = { };
      }
      {
        profileName = "Tokyo";
        exeName = "tokyo";
        module = { colorschemes.tokyonight.enable = true; };
      }
      {
        profileName = "Gruv";
        exeName = "gruv";
        module = { colorschemes.gruvbox.enable = true; };
      }
    ];
  };
...
RicSanOP commented 2 weeks ago

After some more digging, I believe the derivation that nixvim produces does not run the postInstall hook which is why I cannot rename the output executable. @GaetanLepage @MattSturgeon please feel free to evaluate my above module and also give guidance on how we can modify the above or nixvim itself to make this a possibility. As I mentioned before, I am willing to contribute but would appreciate some initial guidance.