Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Per-project LSP with nixvimExtend #1

Open
robbins opened this issue May 29, 2024 · 3 comments
Open

Per-project LSP with nixvimExtend #1

robbins opened this issue May 29, 2024 · 3 comments

Comments

@robbins
Copy link

robbins commented May 29, 2024

In summary though, I have nixvim in a module,
but it's actually installed and exposed as a package using
nixvim.makeNixvimWithModule. This sets up my base config, and in each of my
projects I use olistrik.packages.nixvim.nixvimExtend to add LSP support and
per project/language configuration.

Do you have an example of how you do this? It sounds super interesting :)

@olistrik
Copy link
Owner

@robbins sure!

This is a flake.nix that I use in typescript projects:

{
  inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
  inputs.flake-utils.url = "github:numtide/flake-utils";
  inputs.olistrik.url = "github:olistrik/nixos-config";

  outputs = { self, flake-utils, nixpkgs, ... }@inputs:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = import nixpkgs {
          inherit system;
          overlays = [ inputs.olistrik.overlays.default ];
        };
        nixvim = pkgs.olistrik.nixvim.nixvimExtend {
          config = {
            opts = {
              backupcopy = "yes"; # bun --watch gets very annoyed without this.
            };

            olistrik.plugins = {
              lsp.enable = true; # enable my lsp keybindings.
            };
            
            plugins = {
              gitblame.enable = true;
               
               # enable the builtin ts/js lsp servers.
              lsp.servers = { 
                eslint.enable = true;
                tsserver.enable = true;
              };
            };
          };
        };
      in
      {
        devShell = pkgs.mkShell {
          packages = [ nixvim ];
        };
      });
}

I usually put this in a gitignored <project>/.local/flake.nix so that I'm not interfering with the repositories own flake.nix and so I don't force my nvim config on other contributors. Then as I use direnv I configure my <project>/.envrc with:

# use the projects devenv.
use flake . 

# .local is git ignored, so manually add direnv watchers to the flake files.
watch_file .local/flake.nix .local/flake.lock

# use my .local flake, but as a path because it's not tracked by git.
use flake path:.local

It's not perfect, I'd like to get my devshell flakes to resolve their inputs to match my system inputs. Unless I manually update all of my devshell flakes when I update my system, I wind up with a different nixpkgs/unstable referenced for each project, and making changes to the default nvim config in my system config won't propagate to the devshells until I've pushed it to git and updated the shells. I'm looking into solutions for that though.

@robbins
Copy link
Author

robbins commented May 30, 2024

Thanks, I see, so you can access the derivation of your system Nvim config and modify it in the devshell. I might start doing something like this.

Regarding your last paragraph, if I'm understanding correctly, the opposite side of that problem where you use the same nixpkgs/unstable reference from your system flake in all devshells has the issue of having devshells rebuild in unfortunate moments and the previous closure was GC'd, requiring sometimes large downloads.

I think the best solution might be to have your NixVim config be a separate flake that you consume from your devshells and your system configuration - that way updates can stay in sync without rebuilding everything else.

@olistrik
Copy link
Owner

olistrik commented Jun 4, 2024

@robbins I've worked it out!

I haven't tried without it, but I think that adding your system flake to the registry is a requirement for this to work:

nix.registry.olistrik.flake = self;

This is a snippet of my new .local/flake,

{
  description = "Project specific config for nixvim";

  inputs = {
    olistrik.url = "olistrik"; # references my installed system flake.
    nixpkgs.follows = "olistrik/unstable"; // use the same nixpkgs as my system. 
    flake-utils.url = "github:numtide/flake-utils";
    project = {
      url = "path:/home/oli/.../some-flake-project"; # I haven't gotten this to work without the absolute path.
      inputs = {
        nixpkgs.follows = "nixpkgs";
        flake-utils.follows = "flake-utils";
      };
    };
  };

  outputs = { self, flake-utils, nixpkgs, project, ... }@inputs:
    flake-utils.lib.eachDefaultSystem (system:
      let
        # ... same as before
      in
      {
        devShells.default = pkgs.mkShell {
          # this extends the projects own devshell, shellHooks included!
          inputsFrom = [ project.devShells.${system}.default ];
          packages = [ nixvim ];
        };
      });
}

[...] the issue of having devshells rebuild in unfortunate moments and the previous closure was GC'd, requiring sometimes large downloads.

This shouldn't be an issue, it still creates a lock file and pins a specific revision of my system flake. If I do a system update, the system will change to use a different store path, this project will still reference it as a gcroot.
Honestly I wouldn't mind it if updating my system would update all the projects that reference it a major part of why I'm doing this is that I have a lot of "duplicate" store paths and it's eating up a lot of storage. But I can probably make a script does that from the gc-roots.

[...] have your NixVim config be a separate flake [...]

This is a good idea, i've notice that using my flake pulls in a tone of dependencies because of all the inputs I have for xyz overlays. Very few are needed for nixvim.

I'm thinking of writing a utility function for my .local flakes that does the whole for-each-system, nixvim extends, and mkShell extension for me to reduce the boilerplate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants