Skip to content

Instantly share code, notes, and snippets.

@nat-418
Last active April 16, 2024 23:40
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nat-418/493d40b807132d2643a7058188bff1ca to your computer and use it in GitHub Desktop.
Save nat-418/493d40b807132d2643a7058188bff1ca to your computer and use it in GitHub Desktop.
Advanced Neovim configuration with Nix and Home Manager

From init.lua to default.nix

In a previous post I explained how to manage Neovim plugins with Nix and Home Manager. In this post I want to go further and show how to migrate Neovim configuration from ~/.config/nvim to ~/.config/home-manager entirely. The end result will be to split our Neovim setup into multiple modules that colocate plugin sourcing and configuration.

If you haven't read the post linked above, do so now. We will assume the configuration of that post as the basis for the rest of the steps.

  1. First, create a new directory at ~/.config/home-manager/nvim and move your existing Home Manager Neovim config to ~/.config/home-manager/nvim/default.nix:
{ pkgs, lib, ...}:

let
  fromGitHub = ref: repo: pkgs.vimUtils.buildVimPluginFrom2Nix {
    pname = "${lib.strings.sanitizeDerivationName repo}";
    version = ref;
    src = builtins.fetchGit {
      url = "https://github.com/${repo}.git";
      ref = ref;
    };
  };
in

{
  programs.neovim = {
    enable = true;
    defaultEditor = true;
    viAlias = true;
    vimAlias = true;
    vimdiffAlias = true;
    plugins = with pkgs.vimPlugins; [
      nvim-lspconfig
      nvim-treesitter.withAllGrammars
      plenary-nvim
      gruvbox-material
      mini-nvim
      (fromGitHub "HEAD" "elihunter173/dirbuf.nvim")
    ];
  };
}
  1. Next, edit ~/.config/home-manager/home.nix and import the new file. Note that Nix looks for default.nix in the directory automatically, so we don't have to specify it.
{ ... }:

{
  imports = [
    ./nvim
  ];

  home = {
    username = "test";
    homeDirectory = "/home/test";
  };
}
  1. Now make a ~/.config/home-manager/functions directory and split out the fromGitHub function into a new file at ~/.config/home-manager/functions/fromGitHub.nix. This will make the function reusable across multiple files.
{user, repo, ref ? "HEAD", buildScript ? ":"}:

let
  pkgs = import <nixpkgs> {};
in

pkgs.vimUtils.buildVimPlugin {
  pname = "${pkgs.lib.strings.sanitizeDerivationName repo}";
  version = ref;
  src = builtins.fetchGit {
    url = "https://github.com/${user}/${repo}.git";
    inherit ref;
  };
  inherit buildScript;
}
  1. Modify ~/.config/home-manager/nvim/default.nix to use the new function file.
# [...]
let
  fromGitHub = import ../functions/fromGitHub.nix;
in
# [...]
  1. Write a new file at ~/.config/home-manager/nvim/colorscheme.nix. The /* lua */ comment will allow LSP and Treesitter to work within the following multiline string, assuming your Neovim configuration is setup correctly.
{ pkgs, ... }:

{
  programs.neovim = {
    plugins = with pkgs.vimPlugins; [
      gruvbox-material
    ];
    extraLuaConfig = /* lua */ ''
      vim.o.termguicolors  = true
      vim.cmd('colorscheme gruvbox-material')
      vim.g.gruvbox_material_background = 'hard'
    '';
  };
}
  1. Import the new file from default.nix and remove the colorscheme plugin from the plugins list.
{ config, pkgs, lib, ...}:

let
  fromGitHub = import ../functions/fromGitHub.nix;
in

{
  imports = [
    ./colorscheme.nix
  ];
  programs.neovim = {
    enable = true;
    defaultEditor = true;
    viAlias = true;
    vimAlias = true;
    vimdiffAlias = true;
    plugins = with pkgs.vimPlugins; [
      nvim-lspconfig
      nvim-treesitter.withAllGrammars
      plenary-nvim
      mini-nvim
      (fromGitHub "HEAD" "elihunter173/dirbuf.nvim")
    ];
  };
}
  1. Repeat the above pattern of moving plugins and config to various imports until all your Neovim configuration is fully within Home Manager. Then run $ home-manager switch -b nvim-backup to let Home Manager produce your Neovim configuration programatically. Now you can stop backing up ~/.config/nvim and rollback your configuration whenever something goes wrong.
@craigjl77
Copy link

Hoping that u can help ... getting strange error on home-manager switch
22:00:23$ hmeb
error:
… while calling the 'derivationStrict' builtin

     at /builtin/derivation.nix:9:12: (source not available)

   … while evaluating derivation 'home-manager-generation'
     whose name attribute is located at /nix/store/lnbafzxw52r0w55hwbcrsdkvk5fymv3l-source/pkgs/stdenv/generic/make-derivation.nix:348:7

   … while evaluating attribute 'buildCommand' of derivation 'home-manager-generation'

     at /nix/store/lnbafzxw52r0w55hwbcrsdkvk5fymv3l-source/pkgs/build-support/trivial-builders/default.nix:87:14:

       86|       enableParallelBuilding = true;
       87|       inherit buildCommand name;
         |              ^
       88|       passAsFile = [ "buildCommand" ]

   (stack trace truncated; use '--show-trace' to show the full trace)

   error: in pure evaluation mode, 'fetchTree' requires a locked input, at «none»:0

builds Ok if I comment out this (fromGitHub "HEAD" "elihunter173/dirbuf.nvim")

@craigjl77
Copy link

This is code from nvim/default.nix

{ config, pkgs, lib, ...}:

let
fromGitHub = ref: repo: pkgs.vimUtils.buildVimPlugin {
pname = "${lib.strings.sanitizeDerivationName repo}";
version = ref;
src = builtins.fetchGit {
url = "https://github.com/${repo}.git";
ref = ref;
};
};
in

{
programs.home-manager.enable = true;
programs.git.enable = true;
programs.neovim = {
enable = true;
defaultEditor = true;
viAlias = true;
vimAlias = true;
vimdiffAlias = true;
plugins = with pkgs.vimPlugins; [
nvim-lspconfig
nvim-treesitter.withAllGrammars
plenary-nvim
gruvbox-material
mini-nvim
neovim-sensible
(fromGitHub "HEAD" "elihunter173/dirbuf.nvim")
];
};
}

@Aadniz
Copy link

Aadniz commented Jan 8, 2024

Hoping that u can help ... getting strange error on home-manager switch 22:00:23$ hmeb error: … while calling the 'derivationStrict' builtin

     at /builtin/derivation.nix:9:12: (source not available)

   … while evaluating derivation 'home-manager-generation'
     whose name attribute is located at /nix/store/lnbafzxw52r0w55hwbcrsdkvk5fymv3l-source/pkgs/stdenv/generic/make-derivation.nix:348:7

   … while evaluating attribute 'buildCommand' of derivation 'home-manager-generation'

     at /nix/store/lnbafzxw52r0w55hwbcrsdkvk5fymv3l-source/pkgs/build-support/trivial-builders/default.nix:87:14:

       86|       enableParallelBuilding = true;
       87|       inherit buildCommand name;
         |              ^
       88|       passAsFile = [ "buildCommand" ]

   (stack trace truncated; use '--show-trace' to show the full trace)

   error: in pure evaluation mode, 'fetchTree' requires a locked input, at «none»:0

builds Ok if I comment out this (fromGitHub "HEAD" "elihunter173/dirbuf.nvim")

Guessing this error is coming from src = builtins.fetchGit { ....

These NixOS errors are cryptic...

@felixyz
Copy link

felixyz commented Jan 11, 2024

The new fromGitHub function must be called like so:

  (fromGitHub {user = "elihunter173"; repo = "dirbuf.nvim";})

The ref argument is now optional (as is buildScript).

@NeilDarach
Copy link

This appears to be the flake-compatible version of fetchFromGit

fetchFromGit.nix:

{pkgs, user, repo, ref, rev, buildScript ? ":"}: 
  pkgs.vimUtils.buildVimPlugin {
    pname = "${pkgs.lib.strings.sanitizeDerivationName repo}"; 
    version = ref;
    src = builtins.fetchGit { 
      url = "https://github.com/${user}/${repo}.git";
      rev = rev;
      inherit ref;
      };
    inherit buildScript;
    }

default.nix:

(fromGitHub { inherit pkgs; rev="ac7ad3c8e61630d15af1f6266441984f54f54fd2"; ref="main"; user="elihunter173"; repo="dirbuf.nvim"; })

I'd love to hear if this isn't correct. I'm still at the stage of poking the file until the error goes away.

@nat-418
Copy link
Author

nat-418 commented Apr 16, 2024

I'd love to hear if this isn't correct. I'm still at the stage of poking the file until the error goes away.

I don't use flakes and I don't recommend others use flakes, so I'm afraid I can't be of much help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment