1    =======================================================================================
2    Flake Help                                                      nixCats.flake
3    
4    A Lua-natic's Neovim flake, with extra cats! nixCats!
5    
6    This is the documentation for the flake itself.
7    This flake uses Nix for importing plugins, LSPs, dependencies, and more,
8    in place of usual nvim package managers such as packer, lazy or Mason.
9    
10   Everything else is done in a regular Lua config style.
11   Download in flake.nix and then, simply pretend the root of the flake 
12   is the root of your Lua config. 
13   
14   *******************************************************
15   AN IMPORTANT NOTE:
16   
17   <1> When editing the files within the flake directory,
18   Nix will not package a new file if it isn't staged in git.
19   run git add before rebuilding it whenever adding a new file.
20   Using wrapRc = true would mean this also applies to Lua files.
21   Only tracked files will recieve their updates when
22   rebuilt without git add being ran first. New files need to be added.
23   *******************************************************
24   
25   Related:
26   For detecting what was included by 
27   the flake in your Lua, see:
28   :help nixCats
29   
30   stdpath('config') will still point to ~/.config/<configDirName>.
31   But your Lua config will be in the store.
32   This is okay, because most of the reason for a plugin to use
33   it would be to write to it, and we cant write to store paths anyway. 
34   You could use require('nixCats').configDir,
35   or nixCats('nixCats_config_location')
36   to get current config directory for your uses, if ever necessary.
37   It will be present and correct regardless of settings.
38   
39   However if you did not use Nix at all and did not run the setup
40   function, of course the nixCats plugin wont be there to ask.
41   
42   The setup function from require('nixCatsUtils').setup
43   will provide a mock nixCats plugin with SOME values
44   and empty tables to prevent accidental indexing errors.
45   You could instead do require('nixCatsUtils').isNixCats to default to
46   vim.fn.stdpath('config') if all you wanted was this path though.
47   
48   Keep in mind they will be read-only if in the store!
49   
50   =======================================================================================
51   Flake Inputs:                                            nixCats.flake.inputs
52   
53   If a plugin does not have an extra build step, and are not on nixpkgs,
54   you may use this format to import them, replacing the fields marked with <>
55   
56       "plugins-<pluginName>" = {
57         url = "github:<userName>/<repositoryName>";
58         flake = false;
59       };
60   
61   More info on flake url syntax at:
62   https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html#examples
63   You may also use this syntax to pin the version of a plugin regardless of whether
64   you ran nix flake update or not.
65   You may choose the directory, branch, commit, tag, or even directory
66   imported.
67   
68   All inputs named in the plugins-<pluginName> format will be added to pkgs
69   at pkgs.neovimPlugins.<pluginName> for you to add to your configuration.
70   
71   If the plugin has a dot . character in it's name, you should name it something else
72   because . is not a valid character in an identifier in Nix.
73   
74   The name here only affects the filename of the overall plugin, and should
75   only affect things like vim.cmd("packadd <filename>") that refer to
76   the actual filename of the plugin. Usually I would replace it with -
77   You will then add it to categoryDefinitions later with the NEW name.
78   
79   If you use this method to import a plugin, and really dont
80   want to change the filename of the plugin when they have a
81   dot in their name, you may
82   swap the call to (utils.standardPluginOverlay inputs)
83   with (utils.sanitizedPluginOverlay inputs)
84   and then plugins-plugin.name would become pkgs.neovimPlugins.plugin-name
85   but Neovim would see it as vim.cmd("packadd plugin.name") still
86   
87   If they have a build step or are not a plugin, 
88   i.e. an LSP, or if they are a plugin from a flake,
89   dont name them in that format.
90   If they are a plugin from a flake, they can be added directly,
91   or they may be added as an overlay if offered.
92   If they are anything else they arent a plugin at all and obviously
93   should not be added as a plugin via plugins-<pluginName>
94   
95   If they are on nixpkgs, you dont need to put them in inputs,
96   because you will be able to access them through pkgs.vimPlugins variable.
97   Most plugins will not require you to use the inputs section due to being on nixpkgs.
98   But you may still use it to pin the plugin to a specific version.
99   
100  If you decided not to use utils.sanitizedPluginOverlay
101  and wanted to do it with utils.standardPluginOverlay:
102  If in your inputs you had:
103  
104    "plugins-<plugin-name>" = {
105      url = "github:<userName>/<repository.name>";
106      flake = false;
107    };
108  
109  Where you put plugins in your categoryDefinitions, instead of:
110  
111    pkgs.neovimPlugins.<plugin-name>
112  
113  You could put this:
114  
115    { name = "<plugin.name>"; plugin = pkgs.neovimPlugins.<plugin-name>; }
116  
117  You can also override them instead of (or before/during) the above:
118  
119    (pkgs.neovimPlugins.<plugin-name>.overrideAttrs { pname = "<plugin.name>"; })
120  
121  overrideAttrs can be used for a lot more than just fixing the name of the
122  imported plugin. See:
123  https://ryantm.github.io/nixpkgs/using/overrides/
124  
125  If they have a build step and are not on nixpkgs,
126  you will deal with them in overlays/customBuildsOverlay.nix
127  then import them into a category of the builder. 
128  Alternatively you may use overrideAttrs as mentioned above instead of an
129  overlay for these sorts of packages, but this would possibly get messy if the
130  build step were complex.
131  
132  =======================================================================================
133  Flake Outputs Introduction                              nixCats.flake.outputs
134  
135  With our inputs to our flake taken care of:
136  First, we take care of importing our utils set from nixCats.
137  The reason we are doing this now, is so that it can be defined outside of
138  the utils.eachSystem function, and thus we can export it
139  without having to include a system variable when we import it somewhere else.
140  
141  We also define our luaPath, which is the path to be loaded into the store as
142  your new Neovim config directory. (see :help 'rtp' for the directories
143  available for you to use!)
144  
145  We also define our extra_pkg_config, which is used when initializing the
146  nixpkgs instance that will build your Neovim! It's the same one from
147  
148    pkgs = import nixpkgs { inherit system; overlays = []; config = {}; }
149  
150  That is,
151  
152    outputs = { self, nixpkgs, ... }@inputs: let
153      # In the templates, this is inherit (inputs.nixCats) utils;
154      inherit (inputs.nixCats) utils;
155      # path the the store path to be loaded as Neovim config directory
156      luaPath = "${./.}";
157      # used when initializing the nixpkgs instance
158      extra_pkg_config = {
159        # allowUnfree = true;
160      };
161  
162                                             nixCats.flake.outputs.getOverlays
163  
164  Managing the system variable in combination with overlays
165  can be one of the hardest parts of flake usage.
166  This flake resolves our pkgs instance for Neovim itself to help with this,
167  and takes care of passing the correct pkgs instance
168  to the relevant locations later for use in defining your dependencies.
169  
170  
171    dependencyOverlays = (import ./overlays inputs) ++ [
172      (utils.standardPluginOverlay inputs)
173      inputs.neorg-overlay.overlays.default
174      inputs.lz-n.overlays.default
175  
176      # No overlays SHOULD be exported requiring the ${system} variable to access.
177      # However, some are (such as codeium, a free ai plugin)
178  
179      # when other people mess up their overlays
180      # by wrapping them with flake-utils,
181      # you may instead call this function on their overlay.
182      # it will check if it has the system in it.
183      # if so, it will call the function with the system
184      # and return the desired overlay
185      (utils.fixSystemizedOverlay inputs.codeium.overlays
186        (system: inputs.codeium.overlays.${system}.default)
187      )
188    ];
189  
190  
191                                                 nixCats.flake.outputs.overlays
192  utils.standardPluginOverlay
193  Usage of this function to create an overlay is described in:
194  :h nixCats.flake.inputs
195  along with its friend, utils.sanitizedPluginOverlay
196  
197  It takes all the inputs named in the format
198  plugins-somepluginname and makes them into plugins. 
199  Access them to add them to a category of the builder function 
200  with pkgs.neovimPlugins.somepluginname
201  
202  If the plugin doesn't have a build step,
203  and it wasnt on nixpkgs, then use this method.
204  
205  If the plugin does have a build step and isn't on nixpkgs,
206  then you can either make your own overlay from scratch,
207  or you can call overrideAttrs on the generated plugin
208  to add the required items to it.
209  more info at :h nixCats.flake.inputs
210  
211  If you decide you wish to split your customBuildsOverlay up, 
212  see :help nixCats.flake.nixperts.overlays
213  or look at the overlays/default.nix file for advice on how to do that.
214  
215  ---------------------------------------------------------------------------------------
216                                              nixCats.flake.outputs.categories
217  Then we define what is in our categories!
218  This section is a function that takes the package definition for this
219  particular package as an argument.
220  The builder will call it with that argument, you may use it.
221  This allows categoryDefinitions to access their packages categories and settings,
222  which allows categoryDefinitions to be much more dynamic.
223  
224  It also gets mkPlugin = name: src: as an argument. mkPlugin takes a name,
225  and then a src which is any flake input or fetched drv,
226  and it returns a nvim plugin that can be further overriden via overrideAttrs if desired.
227  There is an overlay to do this automatically from flake inputs, mentioned
228  above. But sometimes it can be advantageous to do one of them individually.
229  
230  It also recieves a mkNvimPlugin = src: name: which does the same thing, but
231  with the arguments the wrong way around.
232  It is still present for backwards compatibility.
233  
234  These are the things you can return:
235  
236    categoryDefinitions = { pkgs, settings, categories, extra, name, mkPlugin, mkNvimPlugin, ... }@packageDef: {
237  
238  <startupPlugins>
239    a flexible set of categories, each containing startup plugins.
240    Startup plugins are loaded and can be required.
241    In addition, this can also recieve a superset of the home manager syntax for
242    plugins. see :help nixCats.flake.outputs.categoryDefinitions.schemas below
243    for info
244  
245  <optionalPlugins>
246    a flexible set of categories, each containing optional plugins.
247    Optional plugins need to be added with packadd before being required.
248    Use :NixCats pawsible to see the names to use for packadd
249    In addition, this can also recieve a superset of the home manager syntax for
250    plugins. see :help nixCats.flake.outputs.categoryDefinitions.schemas below
251    for info
252  
253  <lspsAndRuntimeDeps>
254    a flexible set of categories, each containing LSPs or
255    other internal runtime dependencies such as ctags or debuggers
256    these are available to the PATH while within the Neovim program.
257    this includes the Neovim terminal. 
258    lspsAndRuntimeDeps = {
259      # some categories of stuff.
260      general = with pkgs; [
261        universal-ctags
262        ripgrep
263        fd
264      ];
265      go = with pkgs; [
266        gopls
267        gotools
268        go-tools
269        gccgo
270      ];
271    };
272    
273  <sharedLibraries>
274    a flexible set of categories, each containing a derivation for
275    a runtime shared library. Will be prepended to the LD_LIBRARY_PATH variable. 
276    sharedLibraries = {
277      general = {
278        myGitStuff = with pkgs; [ #<- yes you can nest stuff
279          libgit2
280        ];
281      };
282    };
283  
284  <environmentVariables>
285    a flexible set of categories, each containing an ATTRIBUTE SET of 
286    EnvironmentVariableName = "EnvironmentVariableValue"; 
287    environmentVariables = {
288      general = {
289        CATTESTVARDEFAULT = "It worked!";
290      };
291    };
292    
293  <wrapperArgs>
294    a flexible set of categories, each containing escaped lists of wrapper arguments. 
295      wrapperArgs = {
296        yourCategory = [
297          [ "--set" "MYVAR" "test value" ]
298          {
299            value = [ "--set" "MYVAR2" "test value 2" ];
300            priority = 150; # <- the default priority
301          }
302        ];
303        another = [
304          "--suffix"
305          "PATH"
306          "${pkgs.lib.makeBinPath [ pkgs.something ]}" # <- lspsAndRuntimeDeps does this
307        ];
308      };
309    If you don't know what that is, see here:
310  https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/setup-hooks/make-wrapper.sh
311  
312  <extraWrapperArgs>
313    a flexible set of categories, each containing unescaped wrapper arguments. 
314      extraWrapperArgs = {
315        yourCategory = [
316          "--set MYVAR 'test value'"
317          {
318            value = "--set MYVAR2 'test value 2'";
319            priority = 150; # <- the default priority
320          }
321        ];
322      };
323  
324  <extraLuaPackages>
325    a flexible set of categories, each containing FUNCTIONS 
326    that return lists of extra Lua packages.
327    These functions are the same thing that you would pass to lua.withPackages.
328    Is used to populate $LUA_PATH and $LUA_CPATH 
329      extraLuaPackages = {
330        general = [ (lp: [ lp.magick ]) ];
331      };
332  
333  <optionalLuaPreInit>
334    a flexible set of categories, each containing a list of lua strings,
335    or a LIST of sets containing a priority and a string of the format:
336    catname = [ "require('athing')" { config = "require('something')"; priority = 150; } ];
337    (150 is default priority)
338    These will be ran before sourcing your init.lua
339    It is not the recommended way to create Lua for this flake,
340    but it may be useful in editing flake imports 
341    of other already configured setups following the nixCats format.
342  
343  <optionalLuaAdditions>
344    a flexible set of categories, each containing a list of lua strings,
345    or a LIST of sets containing a priority and a string of the format:
346    catname = [ "require('athing')" { config = "require('something')"; priority = 150; } ];
347    (150 is default priority)
348    These will be ran after sourcing your init.lua
349    It is not the recommended way to create Lua for this flake,
350    but it may be useful in editing flake imports 
351    of other already configured setups following the nixCats format.
352  
353  <bashBeforeWrapper>
354    a flexible set of categories, each containing arbitrary Bash code
355    to run before the wrapper starts within the wrapper's Bash environment.
356    # WARNING: only use this if you know what you are doing and why you need
357    to do it. Whenever possible, use wrapperArgs or extraWrapperArgs instead.
358    This section works the same as extraWrapperArgs but for bash.
359  
360  <extraCats>
361    a flexible set of categories, each containing a list of attribute paths,
362    specified as lists of strings. Thus each category would contain a list of
363    lists of strings.
364    Allows inclusion of extra categories contingent on each lists inclusion in the package,
365    and is useful for creating default values for subcategories.
366    For more info, see below at
367    :h nixCats.flake.outputs.categoryDefinitions.default_values
368    # WARNING: use of categories argument in this set will cause infinite recursion
369    # The categories argument of this function is the FINAL value.
370    # You may use it in any of the other sets.
371  
372  <propagatedBuildInputs> 
373    a flexible set of categories, each containing internal BUILD dependencies.
374    Will not be available to the PATH unless in a devShell.
375    # WARNING: USING THIS SECTION WILL CAUSE NVIM TO BUILD FROM SOURCE.
376  }
377  
378  In essence, the contents of each set listed here are filtered
379  based on the packageDefinitions set you provide, 
380  whereby including categoryname = true; you enable that category.
381  :help nixCats.flake.outputs.packageDefinitions
382  
383  It will remove duplicate items, so feel free to include the same thing in
384  multiple categories if it suits your purposes.
385  
386  It does this recursively. (explained below)
387  
388  If, inside one of these main sets, you had another set,
389  it would consider that a subcategory, and you could enable it
390  just like you do with a normal category, by setting a value with the
391  corresponding attribute path to true in the category
392  set of nixCats.flake.outputs.packageDefinitions.
393  You can nest them as much as you like, or just have a category that is a
394  single derivation.
395  
396                              nixCats.flake.outputs.categoryDefinitions.schemas
397  
398   You may also use the variables passed to your categoryDefinitions function
399   to get access to the set of categories and settings that are being
400   used to define the current package being built!
401  
402      themer = with pkgs.vimPlugins;
403        (builtins.getAttr packageDef.categories.colorscheme {
404            # Theme switcher without creating a new category
405            "onedark" = onedark-vim;
406            "catppuccin" = catppuccin-nvim;
407          }
408        );
409  
410    In addition to all this, if a plugin is defined within a list, it may
411    instead be defined within an attribute set that also contains config
412    to be ran after sourcing init.lua and optionalLuaAdditions
413    to do this, you may use the following syntax in opt or start sections: 
414      [
415        # you may add a plugin to a category list in any of these ways
416        { plugin = derivation; config.lua = ""; config.vim = "";}
417        { plugin = derivation; config = ""; type = "<viml or lua>"; }
418        { plugin = derivation; config = ""; } # defaults to viml
419        { plugin = derivation; }
420  
421        # all the above options can also accept an optional = bool;
422        # to override its presence in either startupPlugins or optionalPlugins
423  
424        # they can also accept a name = string; to override its name
425  
426        # they can also accept a priority = integer; with low being first
427        # and default of 150
428        # if they contain a config value, it will be ran in that order.
429  
430        # they also may contain a pre = true in order to be ran BEFORE init.lua
431  
432        derivation
433        # plain derivation does not need to be in a list, but it should be
434        # anyway. It could be on its own though and would act as its own
435        # category.
436      ]
437  
438                              nixCats.flake.outputs.categoryDefinitions.default_values
439  
440  There are 2 ways of creating default values in nixCats.
441  
442  #1 Implicit: when value is in another section of categoryDefinitions
443  
444  If in your categoryDefinitions you had the following:
445  
446      environmentVariables = {
447        test = {
448          subtest1 = {
449            CATTESTVAR = "It worked!";
450          };
451          subtest2 = {
452            CATTESTVAR3 = "It didn't work!";
453          };
454        };
455      };
456      extraWrapperArgs = {
457        test = [
458          '' --set CATTESTVAR2 "It worked again!"''
459        ];
460      };
461  
462  And in your packageDefinitions set, under categories, you had the following:
463  
464      test = {
465        subtest1 = true;
466      };
467  
468  you could echo $CATTESTVAR and $CATTESTVAR2 in your terminal to see them.
469  However you could not echo $CATTESTVAR3.
470  
471  All items that are not attributes of the parent set will be included
472  when you enable a subcategory. This includes lists, strings, functions, etc...
473  
474  However, attributes will not and you must explicitly enable all attributes of
475  a subcategory if you set even 1 explicitly.
476  
477  Thus to include CATTESTVAR3, you would have to enable it like so: 
478      test = {
479        subtest1 = true;
480        subtest2 = true;
481      };
482   However, those are all the items in the test category.
483  So instead we can do this to enable all the subcategories in test. 
484      test = true;
485  
486  This applies in many situations. Take this one for example.
487  
488      lspsAndRuntimeDeps = {
489        neonixdev = {
490          inherit (pkgs)
491            nix-doc nil lua-language-server nixd; 
492        };
493      };
494      startupPlugins = {
495        neonixdev = with pkgs.vimPlugins; [
496          neodev-nvim
497          neoconf-nvim
498        ];
499      };
500  
501   If you were to put the following in your packageDefinitions: 
502      neonixdev.nix-doc = true;
503  
504  neodev-nvim and neoconf-nvim would still be included.
505  However, nil, lua-language-server, and nixd would not be!
506  You would need to pick which of those you wanted separately.
507  Sometimes this is the desired behavior.
508  Sometimes it is not and a list of packages would be better suited.
509  
510  This leads us to our second way to make a default value:
511  
512  #2 Explicit: using extraCats section of categoryDefinitions.
513  
514  The extraCats section of categoryDefinitions contains categories of attribute
515  paths. If that category is defined, the categories specified by the attribute
516  paths will also be enabled. This means you could make it so that if you
517  included the go category, it could then enable debug.go and lsp.go for you.
518  But in addition to that, it can be combined with the implicit form of creating
519  default values above in an interesting way.
520  
521    categoryDefinitions = { pkgs, settings, categories, extra, name, ... }@packageDef: {
522      lspsAndRuntimeDeps = {
523        debug = with pkgs; {
524          go = [ delve ];
525        };
526        go = with pkgs; [
527          gopls
528          gotools
529          go-tools
530          gccgo
531        ];
532      };
533      startupPlugins = {
534        debug = with pkgs.vimPlugins; {
535          default = [
536            nvim-dap
537            nvim-dap-ui
538            nvim-dap-virtual-text
539          ];
540          go = [ nvim-dap-go ];
541        };
542      };
543      # WARNING: use of categories argument in this set will cause infinite recursion
544      # The categories argument of this function is the FINAL value.
545      # You may use it in any of the other sets.
546      extraCats = {
547        # due to the implicit form of default values in different sections,
548        # this will enable debug.default
549        # if any subcategory of debug is enabled
550        # thus, enabling debug.go would also enable debug.default
551        debug = [
552          [ "debug" "default" ]
553        ];
554        # and if go is enabled, it enables debug.go
555        # which then enables debug.default
556        go = [ # <- must be in a list
557          [ "debug" "go" ]
558        ];
559      };
560    };
561  
562  If you wish to only enable a value via extraCats if multiple other categories
563  are enabled, the categories in extraCats also accept a set form!
564  
565    extraCats = {
566      # if target.cat is enabled, the list of extra cats is active!
567      target.cat = [ # <- must be a list of (sets or list of strings)
568        # list representing attribute path of category to enable.
569        [ "to" "enable" ]
570        # or as a set
571        {
572          cat = [ "other" "toenable" ]; #<- required if providing the set form
573          # all below conditions, if provided, must be true for the `cat` to be included
574  
575          # true if any containing category of the listed cats are enabled
576          when = [ # <- `when` conditions must be a list of list of strings
577            [ "another" "cat" ]
578          ];
579          # true if any containing OR sub category of the listed cats are enabled
580          cond = [ # <- `cond`-itions must be a list of list of strings
581            [ "other" "category" ]
582          ];
583        }
584      ];
585    };
586  
587  ---------------------------------------------------------------------------------------
588  Package Generation:                           nixCats.flake.outputs.packageDefinitions
589  
590  generate packages by calling that builder function we just created.
591  Place them in the packageDefinitions set.
592  
593  First, pick the set of settings you wish to include.
594  
595  Then, pass it a set of named boolean values like this:
596  { categoryname1 = true; categoryname2 = false; etc... }
597  False may be omitted. True may not.
598  Only true matters for what plugins will be added.
599  
600  These categories are defined in the Builder function above 
601  by placing named lists of plugins in the flexible sets provided.
602  The category names are the names of those lists. 
603  Add a new list, then enable the category here.
604  
605  If you have categories with the same name in 
606  multiple different sets outlined above in the builder,
607  all plugins in those categories will be
608  included when you set "thatname = true;" here.
609  hence, general = true; will include the general lspsAndDeps category,
610  as well as the general startupPlugins category.
611  
612  an example package definition:
613  
614    packageDefinitions = {
615      nixCats = { pkgs, name, ... }: {
616        setting = {
617          wrapRc = true;
618          # nvimSRC = inputs.neovim;
619          aliases = [ "viCat" ];
620        };
621        categories = {
622          custom = true;
623          gitPlugins = true;
624          general = true;
625          neonixdev = true;
626  
627          # this does not have an associated category of plugins, 
628          # but Lua can still check for it
629          lspDebugMode = false;
630  
631          # you could also pass something else and it calls 
632          # builtins.toString on it and passes it in as a string
633          theBestCat = "says meow!!!";
634          # maybe you need to pass a port or path in or something idk.
635          # you could :lua =nixCats("theBestCat")
636          # this nixCats("path.to.val") is the main category check function
637          # and it is built to mirror the Nix category scheme as much as possible
638        };
639        extra = {
640          there_is = "also";
641          an_extra = "table";
642          for = ''if you dont want the main subcategory get function
643            to apply to something, or think it all being in categories is too
644            messy
645          '';
646          you_can = ''nixCats.extra("path.to.val")'';
647          for_safer = ''table access via vim.tbl_get'';
648        };
649      };
650    };
651  
652  You can use the nixCats plugin for the set you define here in your Lua
653  It returns a Lua table of the same format.
654  
655  see :help nixCats
656  
657  For more nuances on enabling categories and subcategories, see above at
658  :help nixCats.flake.outputs.categoryDefinitions.default_values
659  and
660  :help nixCats.flake.outputs.categoryDefinitions.schemas
661  
662  ----------------------------------------------------------------------------------------
663  Settings                                       nixCats.flake.outputs.settings
664  
665  These are the defaults:
666  
667    default_settings = {
668      # YOU ARE IN CHARGE OF MAKING SURE THESE ALIASES DO NOT COLLIDE WITH
669      # ANYTHING ELSE
670      # [ "takes" "a" "list" "of" "strings" "and" "makes" "an" "alias" "for" "each" ];
671      aliases = null;
672  
673      # so that you can see it in the store
674      extraName = "";
675  
676      # see :help nixCats.flake.outputs.settings.hosts (the next section)
677      hosts = {};
678  
679      # do you want to package the Lua from this flake in the store?
680      # or would you rather it just read it in your .config/<configDirName>?
681      # nixCats and this help will work either way.
682      # packages with wrapRc = false are for quick changes to Lua.
683      # it is not for being ran from anywhere via nix run, because the config
684      # was not wrapped with the program.
685      wrapRc = true;
686      # wrapRc may also be set as a string.
687      # That string will become an environment variable
688      # which you are able to set to unwrap the config.
689      # and unset to wrap it again, at runtime.
690      # requires 1 extra syscall to achieve.
691  
692      # What should the name of the folder within standard directories
693      # i.e. .config, .local/share, .local/state, .cache, etc... be?
694      # This option is very useful when you want 
695      # to clone an unwrapped config straight to the .config dir.
696      # It is also helpful to prevent other nvim packages sharing data folders.
697      # see :help `$NVIM_APPNAME`
698      configDirName = "nvim";
699  
700      # Only active when wrapRc = false, this option allows you to specify
701      # an absolute path to the unwrapped config directory.
702      # This is not a Nix path. This is the unwrapped config directory.
703      # This means you are going to need to make
704      # sure that it points the right place on the current machine.
705      unwrappedCfgPath = null;
706      # Will not change anything other than config directory, configDirName
707      # is still needed for .local/share or .cache and the like
708  
709      # use this to pin a specific Neovim version.
710      # This one will specify the base Neovim derivation to use.
711      neovim-unwrapped = null;
712      # This one will just override the src value of the Neovim in nixpkgs
713      # import it in flake inputs with flake = false,
714      # It will also obviously cause Neovim to build from source.
715      nvimSRC = null;
716  
717      # These 2 options allow you to choose whether the items from nixCats
718      # override your global environment, or the other way around.
719      # true will allow them to inherit, false will cause it to override.
720      suffix-path = true;
721      # ^ causes lspsAndDeps to be added to the END of
722      # PATH instead of the start
723      suffix-LD = true;
724      # ^ causes sharedLibraries to be added to the END of
725      # LD_LIBRARY_PATH instead of the start
726  
727      # plugins in nixpkgs sometimes have extra dependencies added to
728      # .runtimeDeps attribute. By default nixCats will append then to the path,
729      # accepts `"suffix"` or `true` to append to the PATH
730      # accepts `"prefix"` to prepend to the PATH
731      # accepts `false` or `null` to not include them.
732      autowrapRuntimeDeps = "suffix";
733  
734      # plugins in nixpkgs sometimes have extra lua config added to
735      # .passthru.initLua attribute for compatibility.
736      # By default nixCats will run them before your configuration.
737      # accepts `"prefix"` or `true` to run before your configuration
738      # accepts `"suffix"` to run afterwards
739      # accepts `false` or `null` to not include them.
740      autoconfigure = "prefix";
741  
742      # whether to group up treesitter grammars into a single directory,
743      # or leave them as separate plugins.
744      # Defaults to true as it results in
745      # a significant startup time performance boost
746      # Works only on grammars that have been passed through
747      # pkgs.neovimUtils.grammarToPlugin
748      # or pkgs.vimPlugins.nvim-treesitter.withPlugins
749      collate_grammars = true;
750  
751      # plugins in nixpkgs sometimes have extra plugin dependencies added to
752      # .dependencies attribute. By default nixCats will add them.
753      # If for some reason you want to avoid that, set this to false.
754      autoPluginDeps = true;
755  
756      # each package outputs a module via passthru.
757      # this will set the namespace for the module options
758      # by default will be at config.${packagename}
759      moduleNamespace = [ <packagename> ];
760    };
761  
762  QUICK TIP: wrapRc
763  
764  The wrapRc option is very useful for testing Lua changes.
765  It removes the need to stage and rebuild to see your Lua changes reflected.
766  You will still need to rebuild when making changes to Nix regardless of the
767  value of wrapRc.
768  
769  However it also means that the Lua isn't going run if it isn't in the right
770  folder, i.e. when installed and run from GitHub with nix run.
771  
772  If the Lua is not in vim.fn.stdpath('config'), wrapRc = false will not work.
773  By default this is ~/.config/nvim on Linux systems, although we can
774  change nvim to whatever we wish via the configDirName setting.
775  
776  Alternatively, you can set the unwrappedCfgPath option to allow the
777  configuration to be set to an absolute path. You still may want to set
778  the configDirName option anyway to change the data directories,
779  or explicitly keep it the same on both so that they share stuff like auths.
780  
781  The most convenient way to use this is the following:
782  Make a second identical packageDefinition, but with wrapRc disabled.
783  Then install both the wrapped one and unwrapped one with different aliases.
784  When you want to hack in Lua, use unwrapped! When you're done, just rebuild
785  and go back to the wrapped one.
786  
787  The templates/example/flake.nix file from the example config template
788  has an example of this with nixCats and regularCats.
789  
790  Then, when testing Lua changes, you run the other package and have a vanilla
791  Neovim experience, only rebuilding when you install new packages.
792  
793  When you are satisfied, simply rebuild and go back to using the main package,
794  as it was the same except for the single option!
795  
796  --------------------------------------------------------------------------------------
797  Remote Host Providers:                   nixCats.flake.outputs.settings.hosts
798  
799  You can bundle anything with nixCats as a host/provider!
800  Each "host" defined in the hosts set will
801  create a new section in categoryDefinitions,
802  and a global variable of your choosing will be set to the path of the host.
803  
804  Each defined host will also be added to your path as ${nvimname}-${hostname}
805  
806  So if your package was named mynvim,
807  enabling the python3 host will add mynvim-python3 to your path.
808  
809  There are some with builtin defaults.
810  For those, unless you wish to redefine them, you only need to enable them.
811  hosts.python3.enable = true
812  hosts.node.enable = true
813  hosts.ruby.enable = true
814  hosts.perl.enable = true
815  
816  Lets use python3, as an example of a host definition.
817  
818  It will create a section in categoryDefinitions called python3 you can use.
819  The things defined within it will wrap only that host.
820  
821    categoryDefinitions = { pkgs, settings, categories, name, ... }@packageDef: {
822      python3 = {
823        wrapperArgs = {
824          somecatname = [
825            [ "--unset" "PYTHONSAFEPATH" ]
826          ];
827        };
828        extraWrapperArgs = { # <- the same as wrapperArgs but unescaped
829          somecatname = [
830            "--prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.vulkan-loader ]}"
831          ];
832        };
833        envVars = {
834          somecatname = {
835            MY_VAR = "somevalue";
836          };
837        };
838        # only defined if settings.hosts.python3.path is a function
839        # If function passed to the settings.hosts.python3.path function
840        # is called with null as an argument,
841        # libraries categories no longer accept functions
842        libraries = {
843          somecatname = [
844            (p: [p.pytest])
845          ];
846        };
847      };
848    }
849  
850  The definition for the python3 host would look like this when fully spelled out:
851  
852    packageDefinitions = {
853      somename = {pkgs, name, ...}: {
854        settings = {
855          hosts = {
856            python3 = {
857              enable = true; # <- not set by default
858  
859              # REQUIRED:
860              # path can be a string,
861              # or a set:
862              # { value = pkgs.python3; args = [ "extra" "wrapper" "args" ]; nvimArgs = [ "for" "nvim" "itself" ]; }
863              # or a function that returns either type.
864              # If not a function, the ${name}.libraries categoryDefinitions section is ignored
865              path = depfn: {
866                value = (pkgs.python3.withPackages (p: depfn p ++ [p.pynvim])).interpreter;
867                args = [ "--unset" "PYTHONPATH" ];
868              };
869              # depfn returns the result of filtering the
870              # python3.libraries section by categories
871  
872              # the vim.g variable to set to the path of the host.
873              global = "python3_host_prog";
874              # accepts only a string.
875              # the default value is "${name}_host_prog"
876              # and can be omitted if that is the desired value
877  
878              # grabs the named attribute from all included plugins, valid only if path is a function,
879              # included dependencies are returned by the
880              # function your path function recieves in addition to items from ${name}.libraries
881              pluginAttr = "python3Dependencies";
882              # accepts a string, or null.
883              # defaults to null
884              # and can be omitted if that is the desired value
885  
886              # If explicitely disabled, will set this vim.g variable to 0
887              # This is for disabling healthchecks for a provider.
888              # Variable only set if host.${name}.enable = false
889              # can be set to null to prevent it from being set regardless of enable value
890              disabled = "loaded_python3_provider"; # <- the default value
891              # accepts a string, or null.
892              # the default value is "loaded_${name}_provider"
893              # and can be omitted if that is the desired value
894            };
895          };
896        };
897      };
898    };
899  
900  You can bundle and wrap anything this way!
901  
902    packageDefinitions = {
903      packagename = { pkgs, name, mkPlugin, ... }: {
904        categories = {
905        };
906        settings = {
907          hosts = {
908            neovide = {
909              # Will create a `packagename-neovide` in your path that launches the
910              # package named `packagename` in this case.
911              enable = true;
912              path = {
913                value = "${pkgs.neovide}/bin/neovide";
914                args = [ "--add-flags" "--neovim-bin ${name}" ];
915              };
916            };
917          };
918        };
919        extra = {};
920      };
921    };
922  
923  Defaults:
924  
925    defaults = {
926      python3 = {
927        path = depfn: {
928          value = (pkgs.python3.withPackages (p: depfn p ++ [p.pynvim])).interpreter;
929          args = [ "--unset" "PYTHONPATH" ];
930        };
931        pluginAttr = "python3Dependencies";
932      };
933      node = {
934        path = {
935          value = "${pkgs.neovim-node-client or pkgs.nodePackages.neovim}/bin/neovim-node-host";
936          nvimArgs = [ "--suffix" "PATH" ":" "${pkgs.nodejs}/bin" ];
937        };
938      };
939      perl = {
940        path = depfn: "${pkgs.perl.withPackages (p: depfn p ++ [ p.NeovimExt p.Appcpanminus ])}/bin/perl";
941      };
942      ruby = {
943        path = let
944          rubyEnv = pkgs.bundlerEnv {
945            name = "neovim-ruby-env";
946            postBuild = "ln -sf ${pkgs.ruby}/bin/* $out/bin";
947            gemdir = "${pkgs.path}/pkgs/applications/editors/neovim/ruby_provider";
948          };
949        in {
950          value = "${rubyEnv}/bin/neovim-ruby-host";
951          nvimArgs = [
952            "--set" "GEM_HOME" "${rubyEnv}/${rubyEnv.ruby.gemPath}"
953            "--suffix" "PATH" ":" "${rubyEnv}/bin"
954          ];
955        };
956      };
957    };
958  
959  --------------------------------------------------------------------------------------
960  Neovim Builder Creation:                        nixCats.flake.outputs.builder
961  
962  Now we define our builder function.
963  We inherit utils.baseBuilder which is
964  a function that takes five arguments. It is defined in ./builder.
965  Right now we are going to call it with just the first four arguments. This will
966  leave us with a function that takes 1 argument.
967  That argument is the name of the Neovim package to be packaged.
968  
969  1. The path to the Lua to include (in the flake, we use the self variable to get
970       this path and wrap the Lua when wrapRc = true)
971  
972  2. A set containing parameters for the pkgs to be used:
973    It takes 2 forms. You can either pass it a nixpkgs and a system and it
974    will resolve the pkgs for you and pass it to your categoryDefinitions and
975    packageDefinitions,
976    or you can pass it a pkgs instead to inherit the values and do the same.
977  
978    You may also provide a dependencyOverlays list to add overlays for nvim only,
979    extra_pkg_config (maps to the config argument to import nixpkgs { ... }),
980    nixCats_passthru (extra items to put into passthru in the final drv),
981    and extra_pkg_params (contains any fields in import nixpkgs { ... } not mentioned).
982  
983  3. our function that takes an individual package definition
984       and returns a set of categoryDefinitions.
985  
986  4. our set of packageDefinitions see: nixCats.flake.outputs.packageDefinitions
987  
988  It is now a function that takes a name, and returns your chosen Neovim package.
989  
990    packages = nixpkgs.lib.genAttrs nixpkgs.lib.platforms.all (system: let
991      # create our builder for our exports
992      nixCatsBuilder = utils.baseBuilder luaPath {
993        inherit nixpkgs system dependencyOverlays extra_pkg_config;
994      } categoryDefinitions packageDefinitions;
995    in {
996      # it can take a name of a package in packageDefinitions
997      # and return the package!
998      default = nixCatsBuilder defaultPackageName;
999    });
1000 
1001 
1002   packages = nixpkgs.lib.genAttrs nixpkgs.lib.platforms.all (system: let
1003     # create our pkgs to pass to builder
1004     pkgs = import nixpkgs {
1005       inherit system;
1006       overlays = dependencyOverlays;
1007       config = extra_pkg_config;
1008     };
1009     # create our builder for our exports
1010     nixCatsBuilder = utils.baseBuilder luaPath {
1011       /* you can still use dependencyOverlays here and such as well to add */
1012       inherit pkgs; # <- but here we are just going to inherit the value.
1013     } categoryDefinitions packageDefinitions;
1014   in {
1015     # it can take a name of a package in packageDefinitions
1016     # and return the package!
1017     default = nixCatsBuilder defaultPackageName;
1018   });
1019 
1020 ---------------------------------------------------------------------------------------
1021 Flake Exports and Export options               nixCats.flake.outputs.exports
1022 
1023 They look something like this:
1024 
1025   # this first section is the outputs we
1026   # want to wrap with the ${system} variable
1027   utils.eachSystem nixpkgs.lib.platforms.all (system: let
1028     # this is the builder (see :h nixCats.flake.outputs.builder above):
1029     nixCatsBuilder = utils.baseBuilder luaPath {
1030       inherit nixpkgs system dependencyOverlays extra_pkg_config;
1031     } categoryDefinitions packageDefinitions;
1032     # then it takes our categoryDefinitions and packageDefinitions
1033 
1034     # then we build a package to serve as the default one by providing its name.
1035     defaultPackage = nixCatsBuilder defaultPackageName;
1036 
1037     # this is just for using utils in the following section such as pkgs.mkShell
1038     # The one used to build Neovim is resolved inside the builder
1039     # and is passed to our categoryDefinitions and packageDefinitions
1040     pkgs = import nixpkgs { inherit system; };
1041     # as you can see, "resolve pkgs" does not mean anything fancy.
1042     # however, with overlays and system variable,
1043     # sometimes you can get yourself in a loop when
1044     # doing more advanced things. So this flake takes care of that for you.
1045     # it will make sure pkgs is passed to the categoryDefinitions and packageDefinitions
1046   in
1047   {
1048     # these outputs will be wrapped with ${system} by utils.eachSystem
1049 
1050     # this will make a package out of each of the packageDefinitions defined above
1051     # and set the default package to the one passed in here.
1052     packages = utils.mkAllWithDefault defaultPackage;
1053 
1054     # choose your package for devShell
1055     # and add whatever else you want in it.
1056     devShells = {
1057       default = pkgs.mkShell {
1058         name = defaultPackageName;
1059         packages = [ defaultPackage ];
1060         inputsFrom = [ ];
1061         shellHook = ''
1062         '';
1063       };
1064     };
1065 
1066   }) // {
1067 
1068     # these outputs will be NOT wrapped with ${system}
1069 
1070     # now we can export some things that can be imported in other
1071     # flakes, WITHOUT needing to use a system variable to do it.
1072     # and update them into the rest of the outputs returned by the
1073     # eachSystem function.
1074 
1075     # this will make an overlay out of each of the packageDefinitions defined
1076     # and set the default overlay to the one named here.
1077     overlays = utils.makeOverlays luaPath {
1078       # we pass in the things to make a pkgs variable to build nvim with later
1079       inherit nixpkgs dependencyOverlays extra_pkg_config;
1080       # and also our categoryDefinitions
1081     } categoryDefinitions packageDefinitions defaultPackageName;
1082 
1083     # we export a NixOS module to allow configuration from configuration.nix
1084     # allows you to either inherit values from your main flake, or start fresh
1085     # It requires the system variable to build a package but not to build a module!
1086     nixosModules.default = utils.mkNixosModules {
1087       inherit dependencyOverlays luaPath defaultPackageName
1088         categoryDefinitions packageDefinitions nixpkgs;
1089     };
1090     # and the same for Home Manager
1091     homeModule = utils.mkHomeModules {
1092       inherit dependencyOverlays luaPath defaultPackageName
1093         categoryDefinitions packageDefinitions nixpkgs;
1094     };
1095     # and we export these so its super easy to grab them later.
1096     inherit utils;
1097     inherit (utils) templates;
1098   };
1099 
1100                                   nixCats.flake.outputs.utils
1101 
1102 The <utils> set exports all the functions used in creating the format in the
1103 templates, including the main builder!
1104 (see :h nixCats.flake.outputs.builder for builder explanation)
1105 
1106 In the interests of not repeating ourselves,
1107 a list of most functions exported in the <utils> set
1108 can be found here:
1109 https://nixcats.org/nixCats_utils.html
1110 
1111 Missing from that list however,
1112 is an explanation of the internal <n2l> library
1113 nixCats uses to create the nixCats Lua plugin!
1114 
1115 The library fully escapes all items passed to it,
1116 so usually you can't execute lua code in them.
1117 But you may still explicitly pass it lua code to execute at runtime
1118 by declaring them as inline lua types!
1119 
1120 An intricate explanation of the full set
1121 of features the <n2l> library contains are below.
1122 
1123 All other functions made available by
1124 the <utils> set are explained in the documentation
1125 at https://nixcats.org/nixCats_utils.html
1126 
1127                                   nixCats.flake.outputs.utils.n2l
1128 <n2l> This is the Nix to Lua library nixCats
1129 uses to create the nixCats Lua plugin
1130 You may wish to use some functions from it.
1131 
1132 The library is exported from the <utils> set as utils.n2l
1133 
1134 It contains <toLua> and <prettyLua> and <uglyLua> which convert Nix to Lua.
1135 
1136 it contains a <member> function to determine if a value is a special "inline lua" type
1137 it contains a <typeof> function to determine which special "inline lua" type it is
1138 it contains a <resolve> function which knows how to resolve the types to a string of code
1139 it contains the <default_subtype> name as well.
1140 
1141 But of much more interest to you is the types you may declare.
1142 
1143 Everything being passed through settings, categories, and extra in packageDefinitions
1144 will be properly escaped. But this also means that
1145 you cannot write any Lua code there.
1146 
1147 Luckily, we have some types we can declare that will allow you to do this.
1148 
1149 To declare that an item is a Lua value rather than a hard coded one,
1150 you may choose one of these types. To do this, call its constructor!
1151 
1152 for example, types.inline-unsafe has 1 field, body.
1153 
1154 To declare one in our settings, categories, and extra sets, it would look
1155 something like this:
1156 
1157   categories = {
1158     somecat = utils.n2l.types.inline-unsafe.mk {body = "vim.fn.stdpath('data')"; }`
1159   }
1160 
1161 inline-safe is the default type, and it gets to define a shorthand form.
1162 
1163   categories = {
1164     somecat = utils.n2l.types.inline-safe.mk "vim.fn.stdpath('data')";`
1165   }
1166 
1167 These are all the types, each one has an associated mk
1168 function to create a value of that type,
1169 which accepts the fields listed here, defined with default values.
1170 
1171   # creates an inline Lua value in a way that cant break the table
1172   inline-safe = {
1173     default = (v: if v ? body then v else { body = v; });
1174     fields = { body = "nil"; };
1175     format = LI: "assert(loadstring(${luaEnclose "return ${LI.expr.body or LI.expr or "nil"}"}))()";
1176   };
1177   # iterpolates whatever string you provide into the table raw
1178   inline-unsafe = {
1179     fields = { body = "nil"; };
1180     format = LI: "${LI.expr.body or "nil"}";
1181   };
1182   # creates a function with args of the names given in args list
1183   # does so in a way where you cannot accidentally break the table
1184   function-safe = {
1185     fields = { body = "return nil"; args = []; };
1186     format = LI: 
1187       ''assert(loadstring(${luaEnclose ''return (function(${fixargs (LI.expr.args or [])}) ${LI.expr.body or "return nil"} end)''}))()'';
1188   };
1189   # creates a function with args of the names given in args list
1190   # interpolates the body segment raw, just like inline-unsafe, but in a function
1191   function-unsafe = {
1192     fields = { body = "return nil"; args = []; };
1193     format = LI: ''(function(${fixargs (LI.expr.args or [])}) ${LI.expr.body or "return nil"} end)'';
1194   };
1195   with-meta = {
1196     fields = {
1197       table = {}; # <- the table you are adding
1198       meta = {}; # <- the metatable you want to add to it (in Nix)
1199       newtable = null; # <- if you want to specify a different first arg to setmetatable
1200       tablevar = "tbl_in"; # <- varname to refer to the table, to avoid translating multiple times
1201     };
1202     format = LI: opts: let
1203       metaarg1 = if LI.expr.newtable or null == null then LI.expr.tablevar or "{}" else toLuaFull opts LI.expr.newtable;
1204       result = inline.types.function-unsafe.mk {
1205         args = [ (LI.expr.tablevar or "tbl_in") ];
1206         body = ''return setmetatable(${metaarg1}, ${toLuaFull opts LI.expr.meta})'';
1207       };
1208     in "${toLuaFull opts result}(${toLuaFull opts LI.expr.table})";
1209   };
1210 
1211 
1212 Some more useage examples:
1213 
1214   exampleSafeFunc = utils.n2l.types.function-safe.mk {
1215     args = [ "hello" ];
1216     body = /*lua*/ ''
1217       print(hello)
1218       return hi
1219     '';
1220   };
1221   exampleUnsafeFunc = utils.n2l.types.function-unsafe.mk {
1222     args = [ "hi" "hello" ];
1223     body = /*lua*/ ''
1224       print(hi)
1225       print(hello)
1226       return hi .. hello
1227     '';
1228   };
1229   };
1230   funcResults = {
1231     test1 = utils.n2l.types.inline-safe.mk ''${utils.n2l.resolve exampleSafeFunc}("Hello World!")'';
1232   };
1233   lua_table_with_meta = utils.n2l.types.with-meta.mk (let
1234     tablevar = "tbl_in";
1235   in {
1236     table = {
1237       this = "is a test table";
1238       inatesttable = "that will be translated to a Lua table with a metatable";
1239     };
1240     # to avoid translating the table multiple times,
1241     # define a variable name for it in Lua. Defaults to "tbl_in"
1242     inherit tablevar;
1243     meta = {
1244       # __call in Lua lets us also call it like a function
1245       __call = utils.n2l.types.function-unsafe.mk {
1246         args = [ "self" "..." ];
1247         body = ''
1248           print("This table is named ${tablevar}")
1249           return ${tablevar}.this
1250         '';
1251       };
1252     };
1253     # you can change it to set the metatable of
1254     # and return a different table instead.
1255     # sometimes done so that access always uses __index function
1256     newtable = null; # <- default val, sets metatable of tablevar
1257   });
1258 
1259 ---------------------------------------------------------------------------------------
1260 vim:tw=78:ts=8:ft=help:norl: