How to efficiently iterate while developing a flake input

Hi! I’m a nix rookie, so I’d take any general advice. I want to write a vim syntax plugin. It’ll probably live in a publicly accessible repo at some point, but right now it’s just a git+file flake input.

My current workflow is edit plugin file, then sudo nixos-rebuild --flake ~/nixosconfig --update-input vim-mylocalsyntaxplugin switch, then test.

Iterating on this seems to be a huge pain compared to non-nixos environments. Mostly, it’s that it takes 45 seconds for something that would otherwise be an instant vim restart on other systems, and I also have to sudo. I’m wondering if I’m holding it wrong or if there’s some better advice for how to more quickly develop and iterate on items that are flake inputs.

(Thank you!)

Well, you’re rebuilding the whole system to test a vim plugin. You’ll get a very thorough “integration” test here, but that’s indeed bad for cycle times.

You’d probably want to add an app to your flake that just runs a vim instance with this plugin installed, rather than adding this to an existing system (until you want to test the finished product), and start it with e.g. (nix run .#testvim).

Also make sure you use the eval cache, and aren’t doing something silly like an import nixpkgs.

This will still not necessarily be as fast as working directly on your plugin, because nix does need to go through its build cycle. There will always be some overhead involved.

Thanks for the advice, I knew I was missing some piece, and apps in flakes seem a lot more scoped than rebuilding the entire system.

I guess I have a lot more reading to do, as it’s unclear to me how to do this in my flake.nix. Most flakes seem to be providing apps that are sourced from the flake itself and not an executable that comes from some other package. Documentation on apps seems fairly slim. Do you have any pointers to better documentation or tutorials I should be looking at?

(Largely I’m a little bit clear on all steps here: how to find vim’s store path to add it to an app description, have the app include a dependency on that package and plugin [if that’s a thing that even needs to happen], or even add configuration to that app description to set up vim plugin dependencies.)

Yeah, this is a pattern I often use, but the apps feature in general is probably still a bit unexplored in the community. You probably won’t see many examples yet. They also tend to be a bit on the explicit side, which looks ugly in a flake.nix so people probably hide them behind imports a lot.

There’s no convenient little method to create mini-apps from a package yet, but the principle is the same as with making one from packages created within the flake - it’s all just derivations after all.

Here’s an example where I run my web server with the corresponding HTML templates to do a full integration test for my web server: tlaternet-webserver/flake.nix at master - tlaternet-webserver - Forgejo: Beyond coding. We Forge.

In your case, you’d probably do something like this:

{
  description = "tlater.net web server";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11";
  };

  outputs = { self, nixpkgs, ... }: let
    system = "x86_64-linux";
    pkgs = nixpkgs.legacyPackages.${system};
  in {
    # I have no idea how to inject a plugin into vim from the command line
    # Naturally, you can .override the `pkgs.neovim` instead if needed, and
    # that *would* make importing it from a separate file tempting.
    apps.${system}.testvim = pkgs.writeShellScript "testvim" ''
      ${pkgs.neovim}/bin/vim --plugin ${self.packages.${system}.vim-plugin}
    '';
  };
2 Likes