anvil-editor: init at 0.4
[NixPkgs.git] / pkgs / applications / editors / neovim / utils.nix
blob158bc31e8bb3acae163eef06cea5958f3108af06
1 { lib
2 , stdenv
3 , makeSetupHook
4 , callPackage
5 , vimUtils
6 , vimPlugins
7 , nodejs
8 , neovim-unwrapped
9 , bundlerEnv
10 , ruby
11 , lua
12 , python3Packages
13 , wrapNeovimUnstable
15 let
16   inherit (vimUtils) toVimPlugin;
18   /* transform all plugins into an attrset
19    { optional = bool; plugin = package; }
20   */
21   normalizePlugins = plugins:
22       let
23         defaultPlugin = {
24           plugin = null;
25           config = null;
26           optional = false;
27         };
28       in
29         map (x: defaultPlugin // (if (x ? plugin) then x else { plugin = x; })) plugins;
32   /**
33     accepts a list of normalized plugins and convert them into a vim package
35     # Type
37     ```
38     normalizedPluginsToVimPackage :: [AttrSet] -> AttrSet
39     ```
41     # Examples
42     :::{.example}
44     ```nix
45     normalizedPluginsToVimPackage [ { plugin = vim-fugitive; optional = false'} ]
46     => { start = [ vim-fugitive ]; opt = []; }
47     :::
48   */
49   normalizedPluginsToVimPackage = normalizedPlugins:
50     let
51       pluginsPartitioned = lib.partition (x: x.optional == true) normalizedPlugins;
52     in {
53         start = map (x: x.plugin) pluginsPartitioned.wrong;
54         opt = map (x: x.plugin) pluginsPartitioned.right;
55       };
57    /* returns everything needed for the caller to wrap its own neovim:
58    - the generated content of the future init.vim
59    - the arguments to wrap neovim with
60    The caller is responsible for writing the init.vim and adding it to the wrapped
61    arguments (["-u" writeText "init.vim" GENERATEDRC)]).
62    This makes it possible to write the config anywhere: on a per-project basis
63    .nvimrc or in $XDG_CONFIG_HOME/nvim/init.vim to avoid sideeffects.
64    Indeed, note that wrapping with `-u init.vim` has sideeffects like .nvimrc wont be loaded
65    anymore, $MYVIMRC wont be set etc
66    */
67    makeNeovimConfig = {
68       customRC ? ""
69       /* the function you would have passed to lua.withPackages */
70       , extraLuaPackages ? (_: [ ])
71       , ...}@attrs: let
72         luaEnv = neovim-unwrapped.lua.withPackages extraLuaPackages;
73      in attrs // {
74      neovimRcContent = customRC;
75      wrapperArgs = lib.optionals (luaEnv != null) [
76           "--prefix" "LUA_PATH" ";" (neovim-unwrapped.lua.pkgs.luaLib.genLuaPathAbsStr luaEnv)
77           "--prefix" "LUA_CPATH" ";" (neovim-unwrapped.lua.pkgs.luaLib.genLuaCPathAbsStr luaEnv)
78       ];
79    };
82   # to keep backwards compatibility for people using neovim.override
83   legacyWrapper = neovim: {
84     extraMakeWrapperArgs ? ""
85     /* the function you would have passed to python.withPackages */
86     , extraPythonPackages ? (_: [])
87     /* the function you would have passed to python.withPackages */
88     , withPython3 ? true,  extraPython3Packages ? (_: [])
89     /* the function you would have passed to lua.withPackages */
90     , extraLuaPackages ? (_: [])
91     , withNodeJs ? false
92     , withRuby ? true
93     , vimAlias ? false
94     , viAlias ? false
95     , configure ? {}
96     , extraName ? ""
97   }:
98     let
100       # we convert from the old configure.format to
101       plugins = if builtins.hasAttr "plug" configure then
102           throw "The neovim legacy wrapper doesn't support configure.plug anymore, please setup your plugins via 'configure.packages' instead"
103         else
104           lib.flatten (lib.mapAttrsToList genPlugin (configure.packages or {}));
105       genPlugin = packageName: {start ? [], opt ? []}:
106         start ++ (map (p: { plugin = p; optional = true; }) opt);
108       res = makeNeovimConfig {
109         inherit withPython3;
110         inherit extraPython3Packages;
111         inherit extraLuaPackages;
112         inherit withNodeJs withRuby viAlias vimAlias;
113         customRC = configure.customRC or "";
114         inherit plugins;
115         inherit extraName;
116       };
117     in
118     wrapNeovimUnstable neovim (res // {
119       wrapperArgs = lib.escapeShellArgs res.wrapperArgs + " " + extraMakeWrapperArgs;
120       wrapRc = (configure != {});
121   });
123   /* Generate vim.g.<LANG>_host_prog lua rc to setup host providers
125   Mapping a boolean argument to a key that tells us whether to add
126       vim.g.<LANG>_host_prog=$out/bin/nvim-<LANG>
127   Or this:
128       let g:loaded_${prog}_provider=0
129   While the latter tells nvim that this provider is not available */
130   generateProviderRc = {
131       withPython3 ? true
132     , withNodeJs ? false
133     , withRuby ? true
134     # perl is problematic https://github.com/NixOS/nixpkgs/issues/132368
135     , withPerl ? false
137     # so that we can pass the full neovim config while ignoring it
138     , ...
139     }: let
140       hostprog_check_table = {
141         node = withNodeJs;
142         python = false;
143         python3 = withPython3;
144         ruby = withRuby;
145         perl = withPerl;
146       };
148       genProviderCommand = prog: withProg:
149         if withProg then
150           "vim.g.${prog}_host_prog='${placeholder "out"}/bin/nvim-${prog}'"
151         else
152           "vim.g.loaded_${prog}_provider=0";
154       hostProviderLua = lib.mapAttrsToList genProviderCommand hostprog_check_table;
155     in
156         lib.concatStringsSep ";" hostProviderLua;
158   /* Converts a lua package into a neovim plugin.
159     Does so by installing the lua package with a flat hierarchy of folders
160   */
161   buildNeovimPlugin = callPackage ./build-neovim-plugin.nix {
162     inherit (vimUtils) toVimPlugin;
163     inherit lua;
164   };
166   grammarToPlugin = grammar:
167     let
168       name = lib.pipe grammar [
169         lib.getName
171         # added in buildGrammar
172         (lib.removeSuffix "-grammar")
174         # grammars from tree-sitter.builtGrammars
175         (lib.removePrefix "tree-sitter-")
176         (lib.replaceStrings [ "-" ] [ "_" ])
177       ];
179       nvimGrammars = lib.mapAttrsToList (name: value: value.origGrammar) vimPlugins.nvim-treesitter.grammarPlugins;
180       isNvimGrammar = x: builtins.elem x nvimGrammars;
182       toNvimTreesitterGrammar = callPackage ({ }:
183         makeSetupHook {
184           name = "to-nvim-treesitter-grammar";
185         } ./to-nvim-treesitter-grammar.sh) {};
186     in
188     (toVimPlugin (stdenv.mkDerivation {
189       name = "treesitter-grammar-${name}";
191       origGrammar = grammar;
192       grammarName = name;
194       # Queries for nvim-treesitter's (not just tree-sitter's) officially
195       # supported languages are bundled with nvim-treesitter
196       # Queries from repositories for such languages are incompatible
197       # with nvim's implementation of treesitter.
198       #
199       # We try our best effort to only include queries for niche languages
200       # (there are grammars for them in nixpkgs, but they're in
201       # `tree-sitter-grammars.tree-sitter-*`; `vimPlugins.nvim-treesitter-parsers.*`
202       # only includes officially supported languages)
203       #
204       # To use grammar for a niche language, users usually do:
205       #   packages.all.start = with final.vimPlugins; [
206       #     (pkgs.neovimUtils.grammarToPlugin pkgs.tree-sitter-grammars.tree-sitter-LANG)
207       #   ]
208       #
209       # See also https://github.com/NixOS/nixpkgs/pull/344849#issuecomment-2381447839
210       installQueries = !isNvimGrammar grammar;
212       dontUnpack = true;
213       __structuredAttrs = true;
215       nativeBuildInputs = [ toNvimTreesitterGrammar ];
217       meta = {
218         platforms = lib.platforms.all;
219       } // grammar.meta;
220     }));
222   /*
223     Fork of vimUtils.packDir that additionnally generates a propagated-build-inputs-file that
224     can be used by the lua hooks to generate a proper LUA_PATH
226     Generates a packpath folder as expected by vim
227        Example:
228        packDir ( {myVimPackage = { start = [ vimPlugins.vim-fugitive ]; opt = []; }; })
229        => "/nix/store/xxxxx-pack-dir"
230   */
231   packDir = packages:
232   let
233     rawPackDir = vimUtils.packDir packages;
235   in
236     rawPackDir.override ({
237     postBuild = ''
238       mkdir $out/nix-support
239       for i in $(find -L $out -name propagated-build-inputs ); do
240         cat "$i" >> $out/nix-support/propagated-build-inputs
241       done
242       '';});
247   inherit makeNeovimConfig;
248   inherit generateProviderRc;
249   inherit legacyWrapper;
250   inherit grammarToPlugin;
251   inherit packDir;
252   inherit normalizePlugins normalizedPluginsToVimPackage;
254   inherit buildNeovimPlugin;
255   buildNeovimPluginFrom2Nix = lib.warn "buildNeovimPluginFrom2Nix was renamed to buildNeovimPlugin" buildNeovimPlugin;