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 appended to the PATH (by default) while within
257    the Neovim program, including 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        { pre = true; value = 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 appended to the LD_LIBRARY_PATH variable. 
276    sharedLibraries = {
277      general = {
278        myGitStuff = with pkgs; [ #<- yes you can nest stuff
279          libgit2
280          # by default, these are suffixed unless pre = true;
281          # however, you can change that default in settings,
282          # making default prefix, and pre = false to suffix
283          { value = libpng; pre = true; }
284        ];
285      };
286    };
287  
288  <environmentVariables>
289    a flexible set of categories, each containing an ATTRIBUTE SET of 
290    EnvironmentVariableName = "EnvironmentVariableValue"; 
291    environmentVariables = {
292      general = {
293        CATTESTVARDEFAULT = "It worked!";
294      };
295    };
296    
297  <wrapperArgs>
298    a flexible set of categories, each containing escaped lists of wrapper arguments. 
299      wrapperArgs = {
300        yourCategory = [
301          [ "--set" "MYVAR" "test value" ]
302          {
303            value = [ "--set" "MYVAR2" "test value 2" ];
304            priority = 150; # <- the default priority
305          }
306        ];
307        another = [
308          "--suffix"
309          "PATH"
310          "${pkgs.lib.makeBinPath [ pkgs.something ]}" # <- lspsAndRuntimeDeps does this
311        ];
312      };
313    If you don't know what that is, see here:
314  https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/setup-hooks/make-wrapper.sh
315  
316  <extraWrapperArgs>
317    a flexible set of categories, each containing unescaped wrapper arguments. 
318      extraWrapperArgs = {
319        yourCategory = [
320          "--set MYVAR 'test value'"
321          {
322            value = "--set MYVAR2 'test value 2'";
323            priority = 150; # <- the default priority
324          }
325        ];
326      };
327  
328  <extraLuaPackages>
329    a flexible set of categories, each containing FUNCTIONS 
330    that return lists of extra Lua packages.
331    These functions are the same thing that you would pass to lua.withPackages.
332    Is used to populate $LUA_PATH and $LUA_CPATH 
333      extraLuaPackages = {
334        general = [ (lp: [ lp.magick ]) ];
335      };
336  
337  <optionalLuaPreInit>
338    a flexible set of categories, each containing a list of lua strings,
339    or a LIST of sets containing a priority and a string of the format:
340    catname = [ "require('athing')" { config = "require('something')"; priority = 150; } ];
341    (150 is default priority)
342    These will be ran before sourcing your init.lua
343    It is not the recommended way to create Lua for this flake,
344    but it may be useful in editing flake imports 
345    of other already configured setups following the nixCats format.
346  
347  <optionalLuaAdditions>
348    a flexible set of categories, each containing a list of lua strings,
349    or a LIST of sets containing a priority and a string of the format:
350    catname = [ "require('athing')" { config = "require('something')"; priority = 150; } ];
351    (150 is default priority)
352    These will be ran after sourcing your init.lua
353    It is not the recommended way to create Lua for this flake,
354    but it may be useful in editing flake imports 
355    of other already configured setups following the nixCats format.
356  
357  <bashBeforeWrapper>
358    a flexible set of categories, each containing arbitrary Bash code
359    to run before the wrapper starts within the wrapper's Bash environment.
360    # WARNING: only use this if you know what you are doing and why you need
361    to do it. This section works the same as extraWrapperArgs but for bash.
362    # WARNING: This section is disabled when useBinaryWrapper setting is
363    enabled.
364  
365  <extraCats>
366    a flexible set of categories, each containing a list of attribute paths,
367    specified as lists of strings. Thus each category would contain a list of
368    lists of strings.
369    Allows inclusion of extra categories contingent on each lists inclusion in the package,
370    and is useful for creating default values for subcategories.
371    For more info, see below at
372    :h nixCats.flake.outputs.categoryDefinitions.default_values
373    # WARNING: use of categories argument in this set will cause infinite recursion
374    # The categories argument of this function is the FINAL value.
375    # You may use it in any of the other sets.
376  
377  <propagatedBuildInputs> 
378    a flexible set of categories, each containing internal BUILD dependencies.
379    Will not be available to the PATH unless in a devShell.
380    # WARNING: USING THIS SECTION WILL CAUSE NVIM TO BUILD FROM SOURCE.
381  }
382  
383  In essence, the contents of each set listed here are filtered
384  based on the packageDefinitions set you provide, 
385  whereby including categoryname = true; you enable that category.
386  :help nixCats.flake.outputs.packageDefinitions
387  
388  It will remove duplicate items, so feel free to include the same thing in
389  multiple categories if it suits your purposes.
390  
391  It does this recursively. (explained below)
392  
393  If, inside one of these main sets, you had another set,
394  it would consider that a subcategory, and you could enable it
395  just like you do with a normal category, by setting a value with the
396  corresponding attribute path to true in the category
397  set of nixCats.flake.outputs.packageDefinitions.
398  You can nest them as much as you like, or just have a category that is a
399  single derivation.
400  
401                              nixCats.flake.outputs.categoryDefinitions.schemas
402  
403   You may also use the variables passed to your categoryDefinitions function
404   to get access to the set of categories and settings that are being
405   used to define the current package being built!
406  
407      themer = with pkgs.vimPlugins;
408        (builtins.getAttr packageDef.categories.colorscheme {
409            # Theme switcher without creating a new category
410            "onedark" = onedark-vim;
411            "catppuccin" = catppuccin-nvim;
412          }
413        );
414  
415    In addition to all this, if a plugin is defined within a list, it may
416    instead be defined within an attribute set that also contains config
417    to be ran after sourcing init.lua and optionalLuaAdditions
418    to do this, you may use the following syntax in opt or start sections: 
419      [
420        # you may add a plugin to a category list in any of these ways
421        { plugin = derivation; config.lua = ""; config.vim = "";}
422        { plugin = derivation; config = ""; type = "<viml or lua>"; }
423        { plugin = derivation; config = ""; } # defaults to viml
424        { plugin = derivation; }
425  
426        # all the above options can also accept an optional = bool;
427        # to override its presence in either startupPlugins or optionalPlugins
428  
429        # they can also accept a name = string; to override its name
430  
431        # they can also accept a priority = integer; with low being first
432        # and default of 150
433        # if they contain a config value, it will be ran in that order.
434  
435        # they also may contain a pre = true in order to be ran BEFORE init.lua
436  
437        derivation
438        # plain derivation does not need to be in a list, but it should be
439        # anyway. It could be on its own though and would act as its own
440        # category.
441      ]
442  
443                              nixCats.flake.outputs.categoryDefinitions.default_values
444  
445  There are 2 ways of creating default values in nixCats.
446  
447  #1 Implicit: when value is in another section of categoryDefinitions
448  
449  If in your categoryDefinitions you had the following:
450  
451      environmentVariables = {
452        test = {
453          subtest1 = {
454            CATTESTVAR = "It worked!";
455          };
456          subtest2 = {
457            CATTESTVAR3 = "It didn't work!";
458          };
459        };
460      };
461      extraWrapperArgs = {
462        test = [
463          '' --set CATTESTVAR2 "It worked again!"''
464        ];
465      };
466  
467  And in your packageDefinitions set, under categories, you had the following:
468  
469      test = {
470        subtest1 = true;
471      };
472  
473  you could echo $CATTESTVAR and $CATTESTVAR2 in your terminal to see them.
474  However you could not echo $CATTESTVAR3.
475  
476  All items that are not attributes of the parent set will be included
477  when you enable a subcategory. This includes lists, strings, functions, etc...
478  
479  However, attributes will not and you must explicitly enable all attributes of
480  a subcategory if you set even 1 explicitly.
481  
482  Thus to include CATTESTVAR3, you would have to enable it like so: 
483      test = {
484        subtest1 = true;
485        subtest2 = true;
486      };
487   However, those are all the items in the test category.
488  So instead we can do this to enable all the subcategories in test. 
489      test = true;
490  
491  This applies in many situations. Take this one for example.
492  
493      lspsAndRuntimeDeps = {
494        neonixdev = {
495          inherit (pkgs)
496            nix-doc nil lua-language-server nixd; 
497        };
498      };
499      startupPlugins = {
500        neonixdev = with pkgs.vimPlugins; [
501          neodev-nvim
502          neoconf-nvim
503        ];
504      };
505  
506   If you were to put the following in your packageDefinitions: 
507      neonixdev.nix-doc = true;
508  
509  neodev-nvim and neoconf-nvim would still be included.
510  However, nil, lua-language-server, and nixd would not be!
511  You would need to pick which of those you wanted separately.
512  Sometimes this is the desired behavior.
513  Sometimes it is not and a list of packages would be better suited.
514  
515  This leads us to our second way to make a default value:
516  
517  #2 Explicit: using extraCats section of categoryDefinitions.
518  
519  The extraCats section of categoryDefinitions contains categories of attribute
520  paths. If that category is defined, the categories specified by the attribute
521  paths will also be enabled. This means you could make it so that if you
522  included the go category, it could then enable debug.go and lsp.go for you.
523  But in addition to that, it can be combined with the implicit form of creating
524  default values above in an interesting way.
525  
526    categoryDefinitions = { pkgs, settings, categories, extra, name, ... }@packageDef: {
527      lspsAndRuntimeDeps = {
528        debug = with pkgs; {
529          go = [ delve ];
530        };
531        go = with pkgs; [
532          gopls
533          gotools
534          go-tools
535          gccgo
536        ];
537      };
538      startupPlugins = {
539        debug = with pkgs.vimPlugins; {
540          default = [
541            nvim-dap
542            nvim-dap-ui
543            nvim-dap-virtual-text
544          ];
545          go = [ nvim-dap-go ];
546        };
547      };
548      # WARNING: use of categories argument in this set will cause infinite recursion
549      # The categories argument of this function is the FINAL value.
550      # You may use it in any of the other sets.
551      extraCats = {
552        # due to the implicit form of default values in different sections,
553        # this will enable debug.default
554        # if any subcategory of debug is enabled
555        # thus, enabling debug.go would also enable debug.default
556        debug = [
557          [ "debug" "default" ]
558        ];
559        # and if go is enabled, it enables debug.go
560        # which then enables debug.default
561        go = [ # <- must be in a list
562          [ "debug" "go" ]
563        ];
564      };
565    };
566  
567  If you wish to only enable a value via extraCats if multiple other categories
568  are enabled, the categories in extraCats also accept a set form!
569  
570    extraCats = {
571      # if target.cat is enabled, the list of extra cats is active!
572      target.cat = [ # <- must be a list of (sets or list of strings)
573        # list representing attribute path of category to enable.
574        [ "to" "enable" ]
575        # or as a set
576        {
577          cat = [ "other" "toenable" ]; #<- required if providing the set form
578          # all below conditions, if provided, must be true for the `cat` to be included
579  
580          # true if any containing category of the listed cats are enabled
581          when = [ # <- `when` conditions must be a list of list of strings
582            [ "another" "cat" ]
583          ];
584          # true if any containing OR sub category of the listed cats are enabled
585          cond = [ # <- `cond`-itions must be a list of list of strings
586            [ "other" "category" ]
587          ];
588        }
589      ];
590    };
591  
592  ---------------------------------------------------------------------------------------
593  Package Generation:                           nixCats.flake.outputs.packageDefinitions
594  
595  generate packages by calling that builder function we just created.
596  Place them in the packageDefinitions set.
597  
598  First, pick the set of settings you wish to include.
599  
600  Then, pass it a set of named boolean values like this:
601  { categoryname1 = true; categoryname2 = false; etc... }
602  False may be omitted. True may not.
603  Only true matters for what plugins will be added.
604  
605  These categories are defined in the Builder function above 
606  by placing named lists of plugins in the flexible sets provided.
607  The category names are the names of those lists. 
608  Add a new list, then enable the category here.
609  
610  If you have categories with the same name in 
611  multiple different sets outlined above in the builder,
612  all plugins in those categories will be
613  included when you set "thatname = true;" here.
614  hence, general = true; will include the general lspsAndDeps category,
615  as well as the general startupPlugins category.
616  
617  an example package definition:
618  
619    packageDefinitions = {
620      # These are all the arguments available to package definition functions
621      # (`this` is the resulting set, be careful with that one!)
622      nixCats = { pkgs, name, mkPlugin, luaPath, this, ... }: {
623        setting = {
624          wrapRc = true;
625          # nvimSRC = inputs.neovim;
626          aliases = [ "viCat" ];
627        };
628        categories = {
629          custom = true;
630          gitPlugins = true;
631          general = true;
632          neonixdev = true;
633  
634          # this does not have an associated category of plugins, 
635          # but Lua can still check for it
636          lspDebugMode = false;
637  
638          # you could also pass something else and it calls 
639          # builtins.toString on it and passes it in as a string
640          theBestCat = "says meow!!!";
641          # maybe you need to pass a port or path in or something idk.
642          # you could :lua =nixCats("theBestCat")
643          # this nixCats("path.to.val") is the main category check function
644          # and it is built to mirror the Nix category scheme as much as possible
645        };
646        extra = {
647          there_is = "also";
648          an_extra = "table";
649          for = ''if you dont want the main subcategory get function
650            to apply to something, or think it all being in categories is too
651            messy
652          '';
653          you_can = ''nixCats.extra("path.to.val")'';
654          for_safer = ''table access via vim.tbl_get'';
655        };
656      };
657    };
658  
659  You can use the nixCats plugin for the set you define here in your Lua
660  It returns a Lua table of the same format.
661  
662  see :help nixCats
663  
664  For more nuances on enabling categories and subcategories, see above at
665  :help nixCats.flake.outputs.categoryDefinitions.default_values
666  and
667  :help nixCats.flake.outputs.categoryDefinitions.schemas
668  
669  ----------------------------------------------------------------------------------------
670  Settings                                       nixCats.flake.outputs.settings
671  
672  These are the defaults:
673  
674    default_settings = {
675      # YOU ARE IN CHARGE OF MAKING SURE THESE ALIASES DO NOT COLLIDE WITH
676      # ANYTHING ELSE
677      # [ "takes" "a" "list" "of" "strings" "and" "makes" "an" "alias" "for" "each" ];
678      aliases = null;
679  
680      # so that you can see it in the store
681      extraName = "";
682  
683      # see :help nixCats.flake.outputs.settings.hosts (the next section)
684      hosts = {};
685  
686      # do you want to package the Lua from this flake in the store?
687      # or would you rather it just read it in your .config/<configDirName>?
688      # nixCats and this help will work either way.
689      # packages with wrapRc = false are for quick changes to Lua.
690      # it is not for being ran from anywhere via nix run, because the config
691      # was not wrapped with the program.
692      wrapRc = true;
693      # wrapRc may also be set as a string.
694      # That string will become an environment variable
695      # which you are able to set to unwrap the config.
696      # and unset to wrap it again, at runtime.
697      # requires 1 extra syscall to achieve.
698  
699      # What should the name of the folder within standard directories
700      # i.e. .config, .local/share, .local/state, .cache, etc... be?
701      # This option is very useful when you want 
702      # to clone an unwrapped config straight to the .config dir.
703      # It is also helpful to prevent other nvim packages sharing data folders.
704      # see :help `$NVIM_APPNAME`
705      configDirName = "nvim";
706  
707      # Only active when wrapRc = false, this option allows you to specify
708      # an absolute path to the unwrapped config directory.
709      # This is not a Nix path. This is the unwrapped config directory.
710      # This means you are going to need to make
711      # sure that it points the right place on the current machine.
712      unwrappedCfgPath = null;
713      # Will not change anything other than config directory, configDirName
714      # is still needed for .local/share or .cache and the like
715  
716      # and related, for when wrapRc == true:
717      wrappedCfgPath = null;
718      # if not null, will replace the main luaPath as the wrapped config path
719      # This may be used to apply optional build steps to your config directory per package.
720      # you may get the original `luaPath` in the arguments to your package definition.
721      # if it is a function, it will recieve the same
722      # arguments as packageDefinitions and should return the new path
723  
724      # use this to pin a specific Neovim version.
725      # This one will specify the base Neovim derivation to use.
726      neovim-unwrapped = null;
727      # This one will just override the src value of the Neovim in nixpkgs
728      # import it in flake inputs with flake = false,
729      # It will also obviously cause Neovim to build from source.
730      nvimSRC = null;
731  
732      # These 2 options allow you to choose whether the items from nixCats
733      # override your global environment, or the other way around.
734      # true will allow them to inherit, false will cause it to override.
735      suffix-path = true;
736      # ^ causes lspsAndDeps to be added to the END of
737      # PATH instead of the start
738      suffix-LD = true;
739      # ^ causes sharedLibraries to be added to the END of
740      # LD_LIBRARY_PATH instead of the start
741  
742      # plugins in nixpkgs sometimes have extra dependencies added to
743      # .runtimeDeps attribute. By default nixCats will append then to the path,
744      # accepts `"suffix"` or `true` to append to the PATH
745      # accepts `"prefix"` to prepend to the PATH
746      # accepts `false` or `null` to not include them.
747      autowrapRuntimeDeps = "suffix";
748  
749      # plugins in nixpkgs sometimes have extra lua config added to
750      # .passthru.initLua attribute for compatibility.
751      # By default nixCats will run them before your configuration.
752      # accepts `"prefix"` or `true` to run before your configuration
753      # accepts `"suffix"` to run afterwards
754      # accepts `false` or `null` to not include them.
755      autoconfigure = "prefix";
756  
757      # whether to group up treesitter grammars into a single directory,
758      # or leave them as separate plugins.
759      # Defaults to true as it results in
760      # a significant startup time performance boost
761      # Works only on grammars that have been passed through
762      # pkgs.neovimUtils.grammarToPlugin
763      # or pkgs.vimPlugins.nvim-treesitter.withPlugins
764      collate_grammars = true;
765  
766      # plugins in nixpkgs sometimes have extra plugin dependencies added to
767      # .dependencies attribute. By default nixCats will add them.
768      # If for some reason you want to avoid that, set this to false.
769      autoPluginDeps = true;
770  
771      # If you wish to use neovim as a shebang on darwin,
772      # you will need to use the binary wrapper.
773      # It is not faster, and it is much more limited.
774      useBinaryWrapper = false;
775      # CAUTION: This will have drastic effects on your configuration.
776      # bashBeforeWrapper section in categoryDefinitions will be disabled.
777      # Using `--run` wrapper argument will throw an error on build.
778      # You will no longer be able to use
779      # "quoted strings with spaces"
780      # in your `--add-flags` wrapper arguments.
781      # in addition, there are other differences between the two wrapper generators
782      # see: https://nixos.org/manual/nixpkgs/stable/#fun-makeWrapper
783      # and for more info on quoted strings with spaces
784      # https://github.com/NixOS/nixpkgs/pull/400649
785      # makeShellWrapper (the default)
786      # https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/setup-hooks/make-wrapper.sh
787      # makeBinaryWrapper
788      # https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/ma/makeBinaryWrapper/make-binary-wrapper.sh
789  
790      # each package outputs a module via passthru.
791      # this will set the namespace for the module options
792      # by default will be at config.${packagename}
793      moduleNamespace = [ <packagename> ];
794    };
795  
796  QUICK TIP: wrapRc
797  
798  The wrapRc option is very useful for testing Lua changes.
799  It removes the need to stage and rebuild to see your Lua changes reflected.
800  You will still need to rebuild when making changes to Nix regardless of the
801  value of wrapRc.
802  
803  However it also means that the Lua isn't going run if it isn't in the right
804  folder, i.e. when installed and run from GitHub with nix run.
805  
806  If the Lua is not in vim.fn.stdpath('config'), wrapRc = false will not work.
807  By default this is ~/.config/nvim on Linux systems, although we can
808  change nvim to whatever we wish via the configDirName setting.
809  
810  Alternatively, you can set the unwrappedCfgPath option to allow the
811  configuration to be set to an absolute path. You still may want to set
812  the configDirName option anyway to change the data directories,
813  or explicitly keep it the same on both so that they share stuff like auths.
814  
815  The most convenient way to use this is the following:
816  Make a second identical packageDefinition, but with wrapRc disabled.
817  Then install both the wrapped one and unwrapped one with different aliases.
818  When you want to hack in Lua, use unwrapped! When you're done, just rebuild
819  and go back to the wrapped one.
820  
821  The templates/example/flake.nix file from the example config template
822  has an example of this with nixCats and regularCats.
823  
824  Then, when testing Lua changes, you run the other package and have a vanilla
825  Neovim experience, only rebuilding when you install new packages.
826  
827  When you are satisfied, simply rebuild and go back to using the main package,
828  as it was the same except for the single option!
829  
830  --------------------------------------------------------------------------------------
831  Remote Host Providers:                   nixCats.flake.outputs.settings.hosts
832  
833  You can bundle anything with nixCats as a host/provider!
834  Each "host" defined in the hosts set will
835  create a new section in categoryDefinitions,
836  and a global variable of your choosing will be set to the path of the host.
837  
838  Each defined host will also be added to your path as ${nvimname}-${hostname}
839  
840  So if your package was named mynvim,
841  enabling the python3 host will add mynvim-python3 to your path.
842  
843  There are some with builtin defaults.
844  For those, unless you wish to redefine them, you only need to enable them.
845  hosts.python3.enable = true
846  hosts.node.enable = true
847  hosts.ruby.enable = true
848  hosts.perl.enable = true
849  
850  Lets use python3, as an example of a host definition.
851  
852  It will create a section in categoryDefinitions called python3 you can use.
853  The things defined within it will wrap only that host.
854  
855    categoryDefinitions = { pkgs, settings, categories, name, ... }@packageDef: {
856      python3 = {
857        wrapperArgs = {
858          somecatname = [
859            [ "--unset" "PYTHONSAFEPATH" ]
860          ];
861        };
862        extraWrapperArgs = { # <- the same as wrapperArgs but unescaped
863          somecatname = [
864            "--prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.vulkan-loader ]}"
865          ];
866        };
867        envVars = {
868          somecatname = {
869            MY_VAR = "somevalue";
870          };
871        };
872        # only defined if settings.hosts.python3.path is a function
873        # If function passed to the settings.hosts.python3.path function
874        # is called with null as an argument,
875        # libraries categories no longer accept functions
876        libraries = {
877          somecatname = [
878            (p: [p.pytest])
879          ];
880        };
881      };
882    }
883  
884  The definition for the python3 host would look like this when fully spelled out:
885  
886    packageDefinitions = {
887      somename = {pkgs, name, ...}: {
888        settings = {
889          hosts = {
890            python3 = {
891              enable = true; # <- not set by default
892  
893              # REQUIRED:
894              # path can be a string,
895              # or a set:
896              # { value = pkgs.python3; args = [ "extra" "wrapper" "args" ]; nvimArgs = [ "for" "nvim" "itself" ]; }
897              # or a function that returns either type.
898              # If not a function, the ${name}.libraries categoryDefinitions section is ignored
899              path = depfn: {
900                value = (pkgs.python3.withPackages (p: depfn p ++ [p.pynvim])).interpreter;
901                args = [ "--unset" "PYTHONPATH" ];
902              };
903              # depfn returns the result of filtering the
904              # python3.libraries section by categories
905  
906              # the vim.g variable to set to the path of the host.
907              global = "python3_host_prog";
908              # accepts only a string.
909              # the default value is "${name}_host_prog"
910              # and can be omitted if that is the desired value
911  
912              # grabs the named attribute from all included plugins, valid only if path is a function,
913              # included dependencies are returned by the
914              # function your path function recieves in addition to items from ${name}.libraries
915              pluginAttr = "python3Dependencies";
916              # accepts a string, or null.
917              # defaults to null
918              # and can be omitted if that is the desired value
919  
920              # If explicitely disabled, will set this vim.g variable to 0
921              # This is for disabling healthchecks for a provider.
922              # Variable only set if host.${name}.enable = false
923              # can be set to null to prevent it from being set regardless of enable value
924              disabled = "loaded_python3_provider"; # <- the default value
925              # accepts a string, or null.
926              # the default value is "loaded_${name}_provider"
927              # and can be omitted if that is the desired value
928            };
929          };
930        };
931      };
932    };
933  
934  You can bundle and wrap anything this way!
935  
936    packageDefinitions = {
937      packagename = { pkgs, name, ... }: {
938        categories = {
939        };
940        settings = {
941          hosts = {
942            neovide = {
943              # Will create a `packagename-neovide` in your path that launches the
944              # package named `packagename` in this case.
945              enable = true;
946              path = {
947                value = "${pkgs.neovide}/bin/neovide";
948                args = [ "--add-flags" "--neovim-bin ${name}" ];
949              };
950            };
951          };
952        };
953        extra = {};
954      };
955    };
956  
957  Defaults:
958  
959    defaults = {
960      python3 = {
961        path = depfn: {
962          value = (pkgs.python3.withPackages (p: depfn p ++ [p.pynvim])).interpreter;
963          args = [ "--unset" "PYTHONPATH" ];
964        };
965        pluginAttr = "python3Dependencies";
966      };
967      node = {
968        path = {
969          value = "${pkgs.neovim-node-client or pkgs.nodePackages.neovim}/bin/neovim-node-host";
970          nvimArgs = [ "--suffix" "PATH" ":" "${pkgs.nodejs}/bin" ];
971        };
972      };
973      perl = {
974        path = depfn: "${pkgs.perl.withPackages (p: depfn p ++ [ p.NeovimExt p.Appcpanminus ])}/bin/perl";
975      };
976      ruby = {
977        path = let
978          rubyEnv = pkgs.bundlerEnv {
979            name = "neovim-ruby-env";
980            postBuild = "ln -sf ${pkgs.ruby}/bin/* $out/bin";
981            gemdir = "${pkgs.path}/pkgs/applications/editors/neovim/ruby_provider";
982          };
983        in {
984          value = "${rubyEnv}/bin/neovim-ruby-host";
985          nvimArgs = [
986            "--set" "GEM_HOME" "${rubyEnv}/${rubyEnv.ruby.gemPath}"
987            "--suffix" "PATH" ":" "${rubyEnv}/bin"
988          ];
989        };
990      };
991    };
992  
993  --------------------------------------------------------------------------------------
994  Neovim Builder Creation:                        nixCats.flake.outputs.builder
995  
996  Now we define our builder function.
997  We inherit utils.baseBuilder which is
998  a function that takes five arguments. It is defined in ./builder.
999  Right now we are going to call it with just the first four arguments. This will
1000 leave us with a function that takes 1 argument.
1001 That argument is the name of the Neovim package to be packaged.
1002 
1003 1. The path to the Lua to include (in the flake, we use the self variable to get
1004      this path and wrap the Lua when wrapRc = true)
1005 
1006 2. A set containing parameters for the pkgs to be used:
1007   It takes 2 forms. You can either pass it a nixpkgs and a system and it
1008   will resolve the pkgs for you and pass it to your categoryDefinitions and
1009   packageDefinitions,
1010   or you can pass it a pkgs instead to inherit the values and do the same.
1011 
1012   You may also provide a dependencyOverlays list to add overlays for nvim only,
1013   extra_pkg_config (maps to the config argument to import nixpkgs { ... }),
1014   nixCats_passthru (extra items to put into passthru in the final drv),
1015   and extra_pkg_params (contains any fields in import nixpkgs { ... } not mentioned).
1016 
1017 3. our function that takes an individual package definition
1018      and returns a set of categoryDefinitions.
1019 
1020 4. our set of packageDefinitions see: nixCats.flake.outputs.packageDefinitions
1021 
1022 It is now a function that takes a name, and returns your chosen Neovim package.
1023 
1024   packages = nixpkgs.lib.genAttrs nixpkgs.lib.platforms.all (system: let
1025     # create our builder for our exports
1026     nixCatsBuilder = utils.baseBuilder luaPath {
1027       inherit nixpkgs system dependencyOverlays extra_pkg_config;
1028     } categoryDefinitions packageDefinitions;
1029   in {
1030     # it can take a name of a package in packageDefinitions
1031     # and return the package!
1032     default = nixCatsBuilder defaultPackageName;
1033   });
1034 
1035 
1036   packages = nixpkgs.lib.genAttrs nixpkgs.lib.platforms.all (system: let
1037     # create our pkgs to pass to builder
1038     pkgs = import nixpkgs {
1039       inherit system;
1040       overlays = dependencyOverlays;
1041       config = extra_pkg_config;
1042     };
1043     # create our builder for our exports
1044     nixCatsBuilder = utils.baseBuilder luaPath {
1045       /* you can still use dependencyOverlays here and such as well to add */
1046       inherit pkgs; # <- but here we are just going to inherit the value.
1047     } categoryDefinitions packageDefinitions;
1048   in {
1049     # it can take a name of a package in packageDefinitions
1050     # and return the package!
1051     default = nixCatsBuilder defaultPackageName;
1052   });
1053 
1054 ---------------------------------------------------------------------------------------
1055 Flake Exports and Export options               nixCats.flake.outputs.exports
1056 
1057 They look something like this:
1058 
1059   # this first section is the outputs we
1060   # want to wrap with the ${system} variable
1061   utils.eachSystem nixpkgs.lib.platforms.all (system: let
1062     # this is the builder (see :h nixCats.flake.outputs.builder above):
1063     nixCatsBuilder = utils.baseBuilder luaPath {
1064       inherit nixpkgs system dependencyOverlays extra_pkg_config;
1065     } categoryDefinitions packageDefinitions;
1066     # then it takes our categoryDefinitions and packageDefinitions
1067 
1068     # then we build a package to serve as the default one by providing its name.
1069     defaultPackage = nixCatsBuilder defaultPackageName;
1070 
1071     # this is just for using utils in the following section such as pkgs.mkShell
1072     # The one used to build Neovim is resolved inside the builder
1073     # and is passed to our categoryDefinitions and packageDefinitions
1074     pkgs = import nixpkgs { inherit system; };
1075     # as you can see, "resolve pkgs" does not mean anything fancy.
1076     # however, with overlays and system variable,
1077     # sometimes you can get yourself in a loop when
1078     # doing more advanced things. So this flake takes care of that for you.
1079     # it will make sure pkgs is passed to the categoryDefinitions and packageDefinitions
1080   in
1081   {
1082     # these outputs will be wrapped with ${system} by utils.eachSystem
1083 
1084     # this will make a package out of each of the packageDefinitions defined above
1085     # and set the default package to the one passed in here.
1086     packages = utils.mkAllWithDefault defaultPackage;
1087 
1088     # choose your package for devShell
1089     # and add whatever else you want in it.
1090     devShells = {
1091       default = pkgs.mkShell {
1092         name = defaultPackageName;
1093         packages = [ defaultPackage ];
1094         inputsFrom = [ ];
1095         shellHook = ''
1096         '';
1097       };
1098     };
1099 
1100   }) // {
1101 
1102     # these outputs will be NOT wrapped with ${system}
1103 
1104     # now we can export some things that can be imported in other
1105     # flakes, WITHOUT needing to use a system variable to do it.
1106     # and update them into the rest of the outputs returned by the
1107     # eachSystem function.
1108 
1109     # this will make an overlay out of each of the packageDefinitions defined
1110     # and set the default overlay to the one named here.
1111     overlays = utils.makeOverlays luaPath {
1112       # we pass in the things to make a pkgs variable to build nvim with later
1113       inherit nixpkgs dependencyOverlays extra_pkg_config;
1114       # and also our categoryDefinitions
1115     } categoryDefinitions packageDefinitions defaultPackageName;
1116 
1117     # we export a NixOS module to allow configuration from configuration.nix
1118     # allows you to either inherit values from your main flake, or start fresh
1119     # It requires the system variable to build a package but not to build a module!
1120     nixosModules.default = utils.mkNixosModules {
1121       inherit dependencyOverlays luaPath defaultPackageName
1122         categoryDefinitions packageDefinitions nixpkgs;
1123     };
1124     # and the same for Home Manager
1125     homeModule = utils.mkHomeModules {
1126       inherit dependencyOverlays luaPath defaultPackageName
1127         categoryDefinitions packageDefinitions nixpkgs;
1128     };
1129     # and we export these so its super easy to grab them later.
1130     inherit utils;
1131     inherit (utils) templates;
1132   };
1133 
1134                                   nixCats.flake.outputs.utils
1135 
1136 The <utils> set exports all the functions used in creating the format in the
1137 templates, including the main builder!
1138 (see :h nixCats.flake.outputs.builder for builder explanation)
1139 
1140 In the interests of not repeating ourselves,
1141 a list of most functions exported in the <utils> set
1142 can be found here:
1143 https://nixcats.org/nixCats_utils.html
1144 
1145 Missing from that list however,
1146 is an explanation of the internal <n2l> library
1147 nixCats uses to create the nixCats Lua plugin!
1148 
1149 The library fully escapes all items passed to it,
1150 so usually you can't execute lua code in them.
1151 But you may still explicitly pass it lua code to execute at runtime
1152 by declaring them as inline lua types!
1153 
1154 An intricate explanation of the full set
1155 of features the <n2l> library contains are below.
1156 
1157 All other functions made available by
1158 the <utils> set are explained in the documentation
1159 at https://nixcats.org/nixCats_utils.html
1160 
1161                                   nixCats.flake.outputs.utils.n2l
1162 <n2l> This is the Nix to Lua library nixCats
1163 uses to create the nixCats Lua plugin
1164 You may wish to use some functions from it.
1165 
1166 The library is exported from the <utils> set as utils.n2l
1167 
1168 It contains <toLua> and <prettyLua> and <uglyLua> which convert Nix values to Lua.
1169 It also contains a <toUnpacked> which converts a nix list
1170 to comma separated lua values for function arguments.
1171 
1172 it contains a <member> function to determine if a value is a special "inline lua" type
1173 it contains a <typeof> function to determine which special "inline lua" type it is
1174 it contains a <resolve> function which knows how to resolve the types to a string of code
1175 it contains the <default_subtype> name as well.
1176 
1177 But of much more interest to you is the types you may declare.
1178 
1179 Everything being passed through settings, categories, and extra in packageDefinitions
1180 will be properly escaped. But this also means that
1181 you cannot write any Lua code there.
1182 
1183 Luckily, we have some types we can declare that will allow you to do this.
1184 
1185 To declare that an item is a Lua value rather than a hard coded one,
1186 you may choose one of these types. To do this, call its constructor!
1187 
1188 for example, types.inline-unsafe has 1 field, body.
1189 
1190 To declare one in our settings, categories, and extra sets, it would look
1191 something like this:
1192 
1193   categories = {
1194     somecat = utils.n2l.types.inline-unsafe.mk {body = "vim.fn.stdpath('data')"; }`
1195   }
1196 
1197 inline-safe is the default type, and it gets to define a shorthand form.
1198 
1199   categories = {
1200     somecat = utils.n2l.types.inline-safe.mk "vim.fn.stdpath('data')";`
1201   }
1202 
1203 These are all the types, each one has an associated mk
1204 function to create a value of that type,
1205 which accepts the fields listed here, defined with default values.
1206 
1207   # creates an inline Lua value in a way that cant break the table
1208   inline-safe = {
1209     default = (v: if v ? body then v else { body = v; });
1210     fields = { body = "nil"; };
1211     format = LI: "assert(loadstring(${luaEnclose "return ${LI.expr.body or LI.expr or "nil"}"}))()";
1212   };
1213   # iterpolates whatever string you provide into the table raw
1214   inline-unsafe = {
1215     fields = { body = "nil"; };
1216     format = LI: "${LI.expr.body or "nil"}";
1217   };
1218   # creates a function with args of the names given in args list
1219   # does so in a way where you cannot accidentally break the table
1220   function-safe = {
1221     fields = { body = "return nil"; args = []; };
1222     format = LI: 
1223       ''assert(loadstring(${luaEnclose ''return (function(${fixargs (LI.expr.args or [])}) ${LI.expr.body or "return nil"} end)''}))()'';
1224   };
1225   # creates a function with args of the names given in args list
1226   # interpolates the body segment raw, just like inline-unsafe, but in a function
1227   function-unsafe = {
1228     fields = { body = "return nil"; args = []; };
1229     format = LI: ''(function(${fixargs (LI.expr.args or [])}) ${LI.expr.body or "return nil"} end)'';
1230   };
1231   with-meta = {
1232     fields = {
1233       table = {}; # <- the table you are adding
1234       meta = {}; # <- the metatable you want to add to it (in Nix)
1235       newtable = null; # <- if you want to specify a different first arg to setmetatable
1236       tablevar = "tbl_in"; # <- varname to refer to the table, to avoid translating multiple times
1237     };
1238     format = LI: opts: let
1239       metaarg1 = if LI.expr.newtable or null == null then LI.expr.tablevar or "{}" else toLuaFull opts LI.expr.newtable;
1240       result = inline.types.function-unsafe.mk {
1241         args = [ (LI.expr.tablevar or "tbl_in") ];
1242         body = ''return setmetatable(${metaarg1}, ${toLuaFull opts LI.expr.meta})'';
1243       };
1244     in "${toLuaFull opts result}(${toLuaFull opts LI.expr.table})";
1245   };
1246 
1247 
1248 Some more useage examples:
1249 
1250   exampleSafeFunc = utils.n2l.types.function-safe.mk {
1251     args = [ "hello" ];
1252     body = /*lua*/ ''
1253       print(hello)
1254       return hi
1255     '';
1256   };
1257   exampleUnsafeFunc = utils.n2l.types.function-unsafe.mk {
1258     args = [ "hi" "hello" ];
1259     body = /*lua*/ ''
1260       print(hi)
1261       print(hello)
1262       return hi .. hello
1263     '';
1264   };
1265   };
1266   funcResults = {
1267     test1 = utils.n2l.types.inline-safe.mk ''${utils.n2l.resolve exampleSafeFunc}("Hello World!")'';
1268   };
1269   lua_table_with_meta = utils.n2l.types.with-meta.mk (let
1270     tablevar = "tbl_in";
1271   in {
1272     table = {
1273       this = "is a test table";
1274       inatesttable = "that will be translated to a Lua table with a metatable";
1275     };
1276     # to avoid translating the table multiple times,
1277     # define a variable name for it in Lua. Defaults to "tbl_in"
1278     inherit tablevar;
1279     meta = {
1280       # __call in Lua lets us also call it like a function
1281       __call = utils.n2l.types.function-unsafe.mk {
1282         args = [ "self" "..." ];
1283         body = ''
1284           print("This table is named ${tablevar}")
1285           return ${tablevar}.this
1286         '';
1287       };
1288     };
1289     # you can change it to set the metatable of
1290     # and return a different table instead.
1291     # sometimes done so that access always uses __index function
1292     newtable = null; # <- default val, sets metatable of tablevar
1293   });
1294 
1295 ---------------------------------------------------------------------------------------
1296 vim:tw=78:ts=8:ft=help:norl: