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