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

vimUtils: plugins shouldn't be overrided by dependencies #355680

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

linsui
Copy link
Contributor

@linsui linsui commented Nov 13, 2024

If the plugin has the same directory name with a dependency of another plugin, it shouldn't be overrided by the dependency.

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.11 Release Notes (or backporting 23.11 and 24.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

@teto
Copy link
Member

teto commented Nov 13, 2024

could you share an exemple where it caused problems ?

@linsui
Copy link
Contributor Author

linsui commented Nov 13, 2024

I add an overrided nvim-treesitter with all grammars. Today I added orgmode and it depends on nvim-treesitter with org grammar only. Then all other grammars disappeared because my nvim-treesitter is overrided.

@PerchunPak
Copy link
Member

I add an overrided nvim-treesitter with all grammars. Today I added orgmode and it depends on nvim-treesitter with org grammar only. Then all other grammars disappeared because my nvim-treesitter is overrided.

Could you send an MRE flake please?

@linsui
Copy link
Contributor Author

linsui commented Nov 13, 2024

I don't use flake but you can use this package

{
  symlinkJoin,
  vimPlugins,
  vimUtils,
}:

let
  nvim-treesitter-with-grammars = symlinkJoin {
    name = "nvim-treesitter";
    paths = [
      vimPlugins.nvim-treesitter
    ] ++ vimPlugins.nvim-treesitter.withAllGrammars.dependencies;
  };

  lazyPkgs.all.start = with vimPlugins; [
    nvim-treesitter-with-grammars
    orgmode
  ];
in
vimUtils.packDir lazyPkgs

@PerchunPak
Copy link
Member

Oh it is probably because orgmode specifies dependencies wrongly

dependencies = with self; [ (nvim-treesitter.withPlugins (p: [ p.org ])) ];

It should be

orgmode = super.orgmode.overrideAttrs {
  dependencies = with self; [
    nvim-treesitter
    nvim-treesitter-parsers.org
  ];
  nvimRequireCheck = "orgmode";
};

But this PR is much better and maintainable fix! Will test it when will have opportunity (==please wait for my review before merging)

@PerchunPak
Copy link
Member

PerchunPak commented Nov 15, 2024

Hmm, I cannot reproduce the issue on nixos-unstable (24f0d4a) but with this PR cherry-picked, no grammars are installed

Wrong MRE flake
# flake.nix
{
  inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
  outputs =
    { nixpkgs, ... }:
    let
      forAllSys = nixpkgs.lib.genAttrs nixpkgs.lib.platforms.all;
      overlayMyNeovim = prev: final: {
        myNeovim =
          let
            luaRC =
              final.writeText "init.lua" # lua
                ''
                  vim.schedule(function()
                    vim.g.mapleader = ' '
                    vim.g.maplocalleader = ' '

                    vim.cmd("packadd nvim-treesitter");
                    require("nvim-treesitter.configs").setup({
                      auto_install = false,
                      highlight = {
                        enable = true
                      },
                    })
                    vim.cmd("packadd orgmode");
                    require('orgmode').setup({
                      org_agenda_files = '~/orgfiles/**/*',
                      org_default_notes_file = '~/orgfiles/refile.org',
                    })
                  end)
                '';
          in
          final.wrapNeovim final.neovim-unwrapped {
            configure = {
              customRC = ''lua dofile("${luaRC}")'';
              packages.all.start =
                with final.vimPlugins;
                [
                ];
              packages.all.opt = with final.vimPlugins; [
                nvim-treesitter.withAllGrammars
                orgmode
              ];
            };
            extraMakeWrapperArgs = ''--prefix PATH : "${
              final.lib.makeBinPath (with final; [ stdenv.cc.cc ])
            }"'';
          };
      };
    in
    {
      packages = forAllSys (
        system:
        let
          pkgs = import nixpkgs {
            inherit system;
            overlays = [ overlayMyNeovim ];
          };
        in
        {
          default = pkgs.myNeovim;
        }
      );
    };
}
nix build .#default --override-input nixpkgs ~/dev/nixpkgs/pr-355680

@linsui
Copy link
Contributor Author

linsui commented Nov 15, 2024

My testcase is that all parsers are symlinked into nvim-treesitter. nvim-treesitter.withAllGrammars adds those parsers as dependencies instead. The problem should be fixed now.

[ plugin ] ++ (
lib.unique (builtins.concatLists (map transitiveClosure plugin.dependencies or []))
);
reverseUniq = list: lib.reverseList (lib.unique (lib.reverseList list));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to reverse list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lib.unique keeps the first same element but I want to keep the last one.

@PerchunPak
Copy link
Member

Oh, I missed that you do symlinkJoin. Here is the right MRE flake that reproduces the issue

MRE flake.nix
{
  inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
  outputs =
    { nixpkgs, ... }:
    let
      forAllSys = nixpkgs.lib.genAttrs nixpkgs.lib.platforms.all;
      overlayMyNeovim = prev: final: {
        myNeovim =
          let
            nvim-treesitter-with-grammars = final.symlinkJoin {
              name = "nvim-treesitter";
              paths =
                with final.vimPlugins;
                [
                  nvim-treesitter
                ]
                ++ nvim-treesitter.withAllGrammars.dependencies;
            };

            luaRC =
              final.writeText "init.lua" # lua
                ''
                  vim.schedule(function()
                    vim.g.mapleader = ' '
                    vim.g.maplocalleader = ' '

                    require("nvim-treesitter.configs").setup({
                      auto_install = false,
                      highlight = {
                        enable = true
                      },
                    })
                    require('orgmode').setup({
                      org_agenda_files = '~/orgfiles/**/*',
                      org_default_notes_file = '~/orgfiles/refile.org',
                    })
                  end)
                '';
          in
          final.wrapNeovim final.neovim-unwrapped {
            configure = {
              customRC = ''lua dofile("${luaRC}")'';
              packages.all.start = with final.vimPlugins; [
                nvim-treesitter-with-grammars
                orgmode
              ];
              packages.all.opt =
                with final.vimPlugins;
                [
                ];
            };
            extraMakeWrapperArgs = ''--prefix PATH : "${
              final.lib.makeBinPath (with final; [ stdenv.cc.cc ])
            }"'';
          };
      };
    in
    {
      packages = forAllSys (
        system:
        let
          pkgs = import nixpkgs {
            inherit system;
            overlays = [ overlayMyNeovim ];
          };
        in
        {
          default = pkgs.myNeovim;
        }
      );
    };
}
nix build .#default --override-input nixpkgs ~/dev/nixpkgs/pr-355680

Also, I think this function can be simplified to

  findDependenciesRecursively = plugins: if plugins == [] then [] else let
    # reverse so lib.unique prefers the last duplicate plugin instead of the first one
    getPluginDependencies = plugin: lib.reverseList (plugin.dependencies or []);
  in
    lib.unique ((
      findDependenciesRecursively (lib.concatLists (map getPluginDependencies plugins))
    ) ++ plugins);

No need to reiterate the list for reversing so many times. Also, this returns a reversed list of plugins, but it shouldn't matter?

@linsui
Copy link
Contributor Author

linsui commented Nov 16, 2024

It works for me. :)

@GaetanLepage
Copy link
Contributor

Is this file formatted ?
It looks quite hard to read.
Maybe it would be worth formatting it in the meantime if it's not.

@PerchunPak
Copy link
Member

Formatted this function isn't much better

  findDependenciesRecursively =
    plugins:
    if plugins == [ ] then
      [ ]
    else
      let
        # reverse so lib.unique prefers the last duplicate plugin instead of the first one
        getPluginDependencies = plugin: lib.reverseList (plugin.dependencies or [ ]);
      in
      lib.unique (
        (findDependenciesRecursively (lib.concatLists (map getPluginDependencies plugins))) ++ plugins
      );

@GaetanLepage
Copy link
Contributor

Formatted this function isn't much better

I find this more readable. But maybe it is just me being used to the formatter's style.

@linsui
Copy link
Contributor Author

linsui commented Nov 16, 2024

I formatted the whole file.

@teto
Copy link
Member

teto commented Nov 16, 2024

I haven't reviewd the code but your premise looks odd:

Today I added orgmode and it depends on nvim-treesitter with org grammar only. Then all other grammars disappeared because my nvim-treesitter is overrided.

orgmode doesn't depend on nvim-treesitter
nvim-orgmode/orgmode#217 (comment)

[ ]
else
let
# reverse so lib.unique prefers the last duplicate plugin instead of the first one
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is it better to select the last rather than the first ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems linkFarm only keeps the last entry with the same path.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but your fix might break other people setup where it's more important to get the latter. So isn't the proper fix to warn in case 2 files conflict ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed the problem that the directly specified plugin is not installed but the dependency is kept.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because if we would prefer first element first, we overwrite our plugins with dependencies of other plugins. I tried to come up with an example, but evaluation of this function is too weird for me to understand.

I cannot come up for why you would want your custom plugins to be ignored, while we have a good use case for why you don't

@linsui
Copy link
Contributor Author

linsui commented Nov 16, 2024

dependencies = with self; [ (nvim-treesitter.withPlugins (p: [ p.org ])) ];

I'm not sure how to fix that properly. We can't let orgmode install the treesitter parser by itself on NixOS. By the way, orgmode uses a forked version of the parser.

@khaneliman
Copy link
Contributor

dependencies = with self; [ (nvim-treesitter.withPlugins (p: [ p.org ])) ];

I'm not sure how to fix that properly. We can't let orgmode install the treesitter parser by itself on NixOS. By the way, orgmode uses a forked version of the parser.

We should remove the dependency if upstream has changed.

@figsoda
Copy link
Member

figsoda commented Nov 16, 2024

I don't use flake but you can use this package

{
  symlinkJoin,
  vimPlugins,
  vimUtils,
}:

let
  nvim-treesitter-with-grammars = symlinkJoin {
    name = "nvim-treesitter";
    paths = [
      vimPlugins.nvim-treesitter
    ] ++ vimPlugins.nvim-treesitter.withAllGrammars.dependencies;
  };

  lazyPkgs.all.start = with vimPlugins; [
    nvim-treesitter-with-grammars
    orgmode
  ];
in
vimUtils.packDir lazyPkgs

Try using vimPlugins.nvim-treesitter.withAllGrammars directly instead, that should put all the dependencies in a passthru and wouldn't collide with the original nvim-treesitter

@linsui
Copy link
Contributor Author

linsui commented Nov 16, 2024

Try using vimPlugins.nvim-treesitter.withAllGrammars directly instead, that should put all the dependencies in a passthru and wouldn't collide with the original nvim-treesitter

I do the symlinkJoin trick to make it work properly with lazy.nvim.

@figsoda
Copy link
Member

figsoda commented Nov 16, 2024

I'm not familar with how lazy.nvim works, does it work if you put vimPlugins.nvim-treesitter.withAllGrammars.dependencies in lazyPkgs.all.start alongside the regular nvim-treesitter? If not, could you try using vimPlugins.extend to override the nvim-treesitter in vimPlugins?

@PerchunPak
Copy link
Member

Try using vimPlugins.nvim-treesitter.withAllGrammars directly instead, that should put all the dependencies in a passthru and wouldn't collide with the original nvim-treesitter

I do the symlinkJoin trick to make it work properly with lazy.nvim.

You don't have to use lazy.nvim as it doesn't play well with nix. There are better tools for lazy loading (if you want to use Nix as dependency manager for your plugins), e.g. lz.n or lze. If you really really really want to use lazy.nvim, you can use nixCats which works perfectly with lazy

Symlinking all grammars only improves startup performance a bit, but it creates a lot of other problems

@linsui
Copy link
Contributor Author

linsui commented Nov 16, 2024

does it work if you put vimPlugins.nvim-treesitter.withAllGrammars.dependencies in lazyPkgs.all.start alongside the regular nvim-treesitter?

lazy.nvim lazy loads the plugin from specified path. So it only loads the nvim-treesitter plugin but not those grammars.

If not, could you try using vimPlugins.extend to override the nvim-treesitter in vimPlugins?

I thought this should work. I'm not sure how extend works though. IIUC I can use overlay direcly. This is a good workaround, thanks!

You don't have to use lazy.nvim as it doesn't play well with nix. There are better tools for lazy loading (if you want to use Nix as dependency manager for your plugins), e.g. lz.n or lze. If you really really really want to use lazy.nvim, you can use nixCats which works perfectly with lazy

I use lazy.nvim because I use LazyVim... Thanks for your suggestion!

@PerchunPak
Copy link
Member

lazy.nvim lazy loads the plugin from specified path. So it only loads the nvim-treesitter plugin but not those grammars.

Lazy.nvim shouldn't load grammars, nvim-treesitter does that

@linsui
Copy link
Contributor Author

linsui commented Nov 16, 2024

Lazy.nvim shouldn't load grammars, nvim-treesitter does that

nvim-treesitter can't find them if they are not loaded or in the plugin path.

@figsoda
Copy link
Member

figsoda commented Nov 16, 2024

Another workaround might be to symlink only the grammars into a plugin, and loading both nvim-treesitter and the grammars plugin

@wegank wegank added the 2.status: merge conflict This PR has merge conflicts with the target branch label Dec 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants