{ lib , stdenv , runCommand , writeShellScriptBin , writeTextFile , neovim-unwrapped , makeWrapper , tree-sitter , fd , ripgrep , html-tidy , node-lsp , blink-cmp , fetchFromGitHub , fetchpatch }: let buildNeovimPlugin = attrs: stdenv.mkDerivation ({ forceShare= [ "man" "info" ]; installPhase = '' cp -r . $out if [ -d "$out/doc" ]; then ${neovim-unwrapped}/bin/nvim -N -u NONE -i NONE -n -E -s -V1 -c "helptags $out/doc" +quit! fi ''; } // attrs); extra-treesitter-textobjects = writeTextFile { name = "extra-treesitter-textobjects"; destination = "/queries/ecma/textobjects.scm"; text = '' ;; extends ; consider array elements as @parameter text objects too (array "," @_start . (_) @parameter.inner (#make-range! "parameter.outer" @_start @parameter.inner)) (array . (_) @parameter.inner . ","? @_end (#make-range! "parameter.outer" @parameter.inner @_end)) ''; }; tsc = writeShellScriptBin "tsc" '' if [ -x "./node_modules/.bin/tsc" ]; then exec ./node_modules/.bin/tsc "$@" else exec ${node-lsp}/lib/node_modules/.bin/tsc "$@" fi ''; extraPath = [ fd ripgrep html-tidy node-lsp tsc ]; pinnedPlugins = import ./plugins { inherit buildNeovimPlugin fetchFromGitHub fetchpatch; }; treesitterPlugins = import ./treesitter { inherit lib runCommand fetchFromGitHub tree-sitter; }; plugins = (builtins.filter (p: !p.optional) (lib.attrValues pinnedPlugins)) ++ (lib.attrValues treesitterPlugins) ++ [ extra-treesitter-textobjects blink-cmp ]; optionalPlugins = builtins.filter (p: p.optional) (lib.attrValues pinnedPlugins); generic = { minimal ? false , startPlugins ? [] , optPlugins ? [] , passthru ? {} }: stdenv.mkDerivation { pname = "nvim"; version = neovim-unwrapped.version; initLua = '' vim.g.loaded_python3_provider = 0 vim.g.loaded_ruby_provider = 0 vim.g.loaded_node_provider = 0 vim.g.loaded_perl_provider = 0 vim.o.runtimepath = table.concat({ '${placeholder "out"}/lib', vim.env.VIMRUNTIME, '${placeholder "out"}/lib/after', }, ',') vim.o.packpath = table.concat({ '${placeholder "out"}/lib', vim.env.VIMRUNTIME, }, ',') -- make sure docs in our packpath are marked as help vim.filetype.add({ pattern = { [os.getenv("VIMRUNTIME"):gsub('[%.%-]', '%%%0') .. '/doc/.*%.txt'] = 'help', ['.*/pack/.*/doc/.*%.txt'] = 'help', } }) ${if minimal then "" else "require('user')"} ''; passAsFile = [ "initLua" ]; nativeBuildInputs = [ makeWrapper ]; unpackPhase = ":"; buildPhase = '' # build pack / runtime dir mkdir -p lib/pack/nixpkgs/start ${lib.concatMapStringsSep "\n" (p: '' ln -s "${p}" "lib/pack/nixpkgs/start/${lib.getName p}" '') startPlugins} mkdir -p lib/pack/nixpkgs/opt ${lib.concatMapStringsSep "\n" (p: '' ln -s "${p}" "lib/pack/nixpkgs/opt/${lib.getName p}" '') optPlugins} # copy in config cp -r ${./config}/. lib/ # create config file mkdir etc cp "$initLuaPath" etc/init.lua # symlink in man pages mkdir -p share ln -s ${neovim-unwrapped}/share/man share/man # make bin mkdir bin makeWrapper ${neovim-unwrapped}/bin/nvim bin/nvim \ --prefix PATH : ${lib.makeBinPath extraPath} \ --add-flags -u \ --add-flags $out/etc/init.lua ''; inherit passthru; installPhase = '' mkdir $out cp -r * $out ''; }; in generic { startPlugins = plugins; optPlugins = optionalPlugins; passthru = { minimal = generic { minimal = true; }; }; }