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      nixCats = { pkgs, name, ... }: {
621        setting = {
622          wrapRc = true;
623          # nvimSRC = inputs.neovim;
624          aliases = [ "viCat" ];
625        };
626        categories = {
627          custom = true;
628          gitPlugins = true;
629          general = true;
630          neonixdev = true;
631  
632          # this does not have an associated category of plugins, 
633          # but Lua can still check for it
634          lspDebugMode = false;
635  
636          # you could also pass something else and it calls 
637          # builtins.toString on it and passes it in as a string
638          theBestCat = "says meow!!!";
639          # maybe you need to pass a port or path in or something idk.
640          # you could :lua =nixCats("theBestCat")
641          # this nixCats("path.to.val") is the main category check function
642          # and it is built to mirror the Nix category scheme as much as possible
643        };
644        extra = {
645          there_is = "also";
646          an_extra = "table";
647          for = ''if you dont want the main subcategory get function
648            to apply to something, or think it all being in categories is too
649            messy
650          '';
651          you_can = ''nixCats.extra("path.to.val")'';
652          for_safer = ''table access via vim.tbl_get'';
653        };
654      };
655    };
656  
657  You can use the nixCats plugin for the set you define here in your Lua
658  It returns a Lua table of the same format.
659  
660  see :help nixCats
661  
662  For more nuances on enabling categories and subcategories, see above at
663  :help nixCats.flake.outputs.categoryDefinitions.default_values
664  and
665  :help nixCats.flake.outputs.categoryDefinitions.schemas
666  
667  ----------------------------------------------------------------------------------------
668  Settings                                       nixCats.flake.outputs.settings
669  
670  These are the defaults:
671  
672    default_settings = {
673      # YOU ARE IN CHARGE OF MAKING SURE THESE ALIASES DO NOT COLLIDE WITH
674      # ANYTHING ELSE
675      # [ "takes" "a" "list" "of" "strings" "and" "makes" "an" "alias" "for" "each" ];
676      aliases = null;
677  
678      # so that you can see it in the store
679      extraName = "";
680  
681      # see :help nixCats.flake.outputs.settings.hosts (the next section)
682      hosts = {};
683  
684      # do you want to package the Lua from this flake in the store?
685      # or would you rather it just read it in your .config/<configDirName>?
686      # nixCats and this help will work either way.
687      # packages with wrapRc = false are for quick changes to Lua.
688      # it is not for being ran from anywhere via nix run, because the config
689      # was not wrapped with the program.
690      wrapRc = true;
691      # wrapRc may also be set as a string.
692      # That string will become an environment variable
693      # which you are able to set to unwrap the config.
694      # and unset to wrap it again, at runtime.
695      # requires 1 extra syscall to achieve.
696  
697      # What should the name of the folder within standard directories
698      # i.e. .config, .local/share, .local/state, .cache, etc... be?
699      # This option is very useful when you want 
700      # to clone an unwrapped config straight to the .config dir.
701      # It is also helpful to prevent other nvim packages sharing data folders.
702      # see :help `$NVIM_APPNAME`
703      configDirName = "nvim";
704  
705      # Only active when wrapRc = false, this option allows you to specify
706      # an absolute path to the unwrapped config directory.
707      # This is not a Nix path. This is the unwrapped config directory.
708      # This means you are going to need to make
709      # sure that it points the right place on the current machine.
710      unwrappedCfgPath = null;
711      # Will not change anything other than config directory, configDirName
712      # is still needed for .local/share or .cache and the like
713  
714      # use this to pin a specific Neovim version.
715      # This one will specify the base Neovim derivation to use.
716      neovim-unwrapped = null;
717      # This one will just override the src value of the Neovim in nixpkgs
718      # import it in flake inputs with flake = false,
719      # It will also obviously cause Neovim to build from source.
720      nvimSRC = null;
721  
722      # These 2 options allow you to choose whether the items from nixCats
723      # override your global environment, or the other way around.
724      # true will allow them to inherit, false will cause it to override.
725      suffix-path = true;
726      # ^ causes lspsAndDeps to be added to the END of
727      # PATH instead of the start
728      suffix-LD = true;
729      # ^ causes sharedLibraries to be added to the END of
730      # LD_LIBRARY_PATH instead of the start
731  
732      # plugins in nixpkgs sometimes have extra dependencies added to
733      # .runtimeDeps attribute. By default nixCats will append then to the path,
734      # accepts `"suffix"` or `true` to append to the PATH
735      # accepts `"prefix"` to prepend to the PATH
736      # accepts `false` or `null` to not include them.
737      autowrapRuntimeDeps = "suffix";
738  
739      # plugins in nixpkgs sometimes have extra lua config added to
740      # .passthru.initLua attribute for compatibility.
741      # By default nixCats will run them before your configuration.
742      # accepts `"prefix"` or `true` to run before your configuration
743      # accepts `"suffix"` to run afterwards
744      # accepts `false` or `null` to not include them.
745      autoconfigure = "prefix";
746  
747      # whether to group up treesitter grammars into a single directory,
748      # or leave them as separate plugins.
749      # Defaults to true as it results in
750      # a significant startup time performance boost
751      # Works only on grammars that have been passed through
752      # pkgs.neovimUtils.grammarToPlugin
753      # or pkgs.vimPlugins.nvim-treesitter.withPlugins
754      collate_grammars = true;
755  
756      # plugins in nixpkgs sometimes have extra plugin dependencies added to
757      # .dependencies attribute. By default nixCats will add them.
758      # If for some reason you want to avoid that, set this to false.
759      autoPluginDeps = true;
760  
761      # If you wish to use neovim as a shebang on darwin,
762      # you will need to use the binary wrapper.
763      # It is not faster, and it is much more limited.
764      useBinaryWrapper = false;
765      # CAUTION: This will have drastic effects on your configuration.
766      # bashBeforeWrapper section in categoryDefinitions will be disabled.
767      # Using `--run` wrapper argument will throw an error on build.
768      # You will no longer be able to use
769      # "quoted strings with spaces"
770      # in your `--add-flags` wrapper arguments.
771      # in addition, there are other differences between the two wrapper generators
772      # see: https://nixos.org/manual/nixpkgs/stable/#fun-makeWrapper
773      # and for more info on quoted strings with spaces
774      # https://github.com/NixOS/nixpkgs/pull/400649
775      # makeShellWrapper (the default)
776      # https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/setup-hooks/make-wrapper.sh
777      # makeBinaryWrapper
778      # https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/ma/makeBinaryWrapper/make-binary-wrapper.sh
779  
780      # each package outputs a module via passthru.
781      # this will set the namespace for the module options
782      # by default will be at config.${packagename}
783      moduleNamespace = [ <packagename> ];
784    };
785  
786  QUICK TIP: wrapRc
787  
788  The wrapRc option is very useful for testing Lua changes.
789  It removes the need to stage and rebuild to see your Lua changes reflected.
790  You will still need to rebuild when making changes to Nix regardless of the
791  value of wrapRc.
792  
793  However it also means that the Lua isn't going run if it isn't in the right
794  folder, i.e. when installed and run from GitHub with nix run.
795  
796  If the Lua is not in vim.fn.stdpath('config'), wrapRc = false will not work.
797  By default this is ~/.config/nvim on Linux systems, although we can
798  change nvim to whatever we wish via the configDirName setting.
799  
800  Alternatively, you can set the unwrappedCfgPath option to allow the
801  configuration to be set to an absolute path. You still may want to set
802  the configDirName option anyway to change the data directories,
803  or explicitly keep it the same on both so that they share stuff like auths.
804  
805  The most convenient way to use this is the following:
806  Make a second identical packageDefinition, but with wrapRc disabled.
807  Then install both the wrapped one and unwrapped one with different aliases.
808  When you want to hack in Lua, use unwrapped! When you're done, just rebuild
809  and go back to the wrapped one.
810  
811  The templates/example/flake.nix file from the example config template
812  has an example of this with nixCats and regularCats.
813  
814  Then, when testing Lua changes, you run the other package and have a vanilla
815  Neovim experience, only rebuilding when you install new packages.
816  
817  When you are satisfied, simply rebuild and go back to using the main package,
818  as it was the same except for the single option!
819  
820  --------------------------------------------------------------------------------------
821  Remote Host Providers:                   nixCats.flake.outputs.settings.hosts
822  
823  You can bundle anything with nixCats as a host/provider!
824  Each "host" defined in the hosts set will
825  create a new section in categoryDefinitions,
826  and a global variable of your choosing will be set to the path of the host.
827  
828  Each defined host will also be added to your path as ${nvimname}-${hostname}
829  
830  So if your package was named mynvim,
831  enabling the python3 host will add mynvim-python3 to your path.
832  
833  There are some with builtin defaults.
834  For those, unless you wish to redefine them, you only need to enable them.
835  hosts.python3.enable = true
836  hosts.node.enable = true
837  hosts.ruby.enable = true
838  hosts.perl.enable = true
839  
840  Lets use python3, as an example of a host definition.
841  
842  It will create a section in categoryDefinitions called python3 you can use.
843  The things defined within it will wrap only that host.
844  
845    categoryDefinitions = { pkgs, settings, categories, name, ... }@packageDef: {
846      python3 = {
847        wrapperArgs = {
848          somecatname = [
849            [ "--unset" "PYTHONSAFEPATH" ]
850          ];
851        };
852        extraWrapperArgs = { # <- the same as wrapperArgs but unescaped
853          somecatname = [
854            "--prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.vulkan-loader ]}"
855          ];
856        };
857        envVars = {
858          somecatname = {
859            MY_VAR = "somevalue";
860          };
861        };
862        # only defined if settings.hosts.python3.path is a function
863        # If function passed to the settings.hosts.python3.path function
864        # is called with null as an argument,
865        # libraries categories no longer accept functions
866        libraries = {
867          somecatname = [
868            (p: [p.pytest])
869          ];
870        };
871      };
872    }
873  
874  The definition for the python3 host would look like this when fully spelled out:
875  
876    packageDefinitions = {
877      somename = {pkgs, name, ...}: {
878        settings = {
879          hosts = {
880            python3 = {
881              enable = true; # <- not set by default
882  
883              # REQUIRED:
884              # path can be a string,
885              # or a set:
886              # { value = pkgs.python3; args = [ "extra" "wrapper" "args" ]; nvimArgs = [ "for" "nvim" "itself" ]; }
887              # or a function that returns either type.
888              # If not a function, the ${name}.libraries categoryDefinitions section is ignored
889              path = depfn: {
890                value = (pkgs.python3.withPackages (p: depfn p ++ [p.pynvim])).interpreter;
891                args = [ "--unset" "PYTHONPATH" ];
892              };
893              # depfn returns the result of filtering the
894              # python3.libraries section by categories
895  
896              # the vim.g variable to set to the path of the host.
897              global = "python3_host_prog";
898              # accepts only a string.
899              # the default value is "${name}_host_prog"
900              # and can be omitted if that is the desired value
901  
902              # grabs the named attribute from all included plugins, valid only if path is a function,
903              # included dependencies are returned by the
904              # function your path function recieves in addition to items from ${name}.libraries
905              pluginAttr = "python3Dependencies";
906              # accepts a string, or null.
907              # defaults to null
908              # and can be omitted if that is the desired value
909  
910              # If explicitely disabled, will set this vim.g variable to 0
911              # This is for disabling healthchecks for a provider.
912              # Variable only set if host.${name}.enable = false
913              # can be set to null to prevent it from being set regardless of enable value
914              disabled = "loaded_python3_provider"; # <- the default value
915              # accepts a string, or null.
916              # the default value is "loaded_${name}_provider"
917              # and can be omitted if that is the desired value
918            };
919          };
920        };
921      };
922    };
923  
924  You can bundle and wrap anything this way!
925  
926    packageDefinitions = {
927      packagename = { pkgs, name, mkPlugin, ... }: {
928        categories = {
929        };
930        settings = {
931          hosts = {
932            neovide = {
933              # Will create a `packagename-neovide` in your path that launches the
934              # package named `packagename` in this case.
935              enable = true;
936              path = {
937                value = "${pkgs.neovide}/bin/neovide";
938                args = [ "--add-flags" "--neovim-bin ${name}" ];
939              };
940            };
941          };
942        };
943        extra = {};
944      };
945    };
946  
947  Defaults:
948  
949    defaults = {
950      python3 = {
951        path = depfn: {
952          value = (pkgs.python3.withPackages (p: depfn p ++ [p.pynvim])).interpreter;
953          args = [ "--unset" "PYTHONPATH" ];
954        };
955        pluginAttr = "python3Dependencies";
956      };
957      node = {
958        path = {
959          value = "${pkgs.neovim-node-client or pkgs.nodePackages.neovim}/bin/neovim-node-host";
960          nvimArgs = [ "--suffix" "PATH" ":" "${pkgs.nodejs}/bin" ];
961        };
962      };
963      perl = {
964        path = depfn: "${pkgs.perl.withPackages (p: depfn p ++ [ p.NeovimExt p.Appcpanminus ])}/bin/perl";
965      };
966      ruby = {
967        path = let
968          rubyEnv = pkgs.bundlerEnv {
969            name = "neovim-ruby-env";
970            postBuild = "ln -sf ${pkgs.ruby}/bin/* $out/bin";
971            gemdir = "${pkgs.path}/pkgs/applications/editors/neovim/ruby_provider";
972          };
973        in {
974          value = "${rubyEnv}/bin/neovim-ruby-host";
975          nvimArgs = [
976            "--set" "GEM_HOME" "${rubyEnv}/${rubyEnv.ruby.gemPath}"
977            "--suffix" "PATH" ":" "${rubyEnv}/bin"
978          ];
979        };
980      };
981    };
982  
983  --------------------------------------------------------------------------------------
984  Neovim Builder Creation:                        nixCats.flake.outputs.builder
985  
986  Now we define our builder function.
987  We inherit utils.baseBuilder which is
988  a function that takes five arguments. It is defined in ./builder.
989  Right now we are going to call it with just the first four arguments. This will
990  leave us with a function that takes 1 argument.
991  That argument is the name of the Neovim package to be packaged.
992  
993  1. The path to the Lua to include (in the flake, we use the self variable to get
994       this path and wrap the Lua when wrapRc = true)
995  
996  2. A set containing parameters for the pkgs to be used:
997    It takes 2 forms. You can either pass it a nixpkgs and a system and it
998    will resolve the pkgs for you and pass it to your categoryDefinitions and
999    packageDefinitions,
1000   or you can pass it a pkgs instead to inherit the values and do the same.
1001 
1002   You may also provide a dependencyOverlays list to add overlays for nvim only,
1003   extra_pkg_config (maps to the config argument to import nixpkgs { ... }),
1004   nixCats_passthru (extra items to put into passthru in the final drv),
1005   and extra_pkg_params (contains any fields in import nixpkgs { ... } not mentioned).
1006 
1007 3. our function that takes an individual package definition
1008      and returns a set of categoryDefinitions.
1009 
1010 4. our set of packageDefinitions see: nixCats.flake.outputs.packageDefinitions
1011 
1012 It is now a function that takes a name, and returns your chosen Neovim package.
1013 
1014   packages = nixpkgs.lib.genAttrs nixpkgs.lib.platforms.all (system: let
1015     # create our builder for our exports
1016     nixCatsBuilder = utils.baseBuilder luaPath {
1017       inherit nixpkgs system dependencyOverlays extra_pkg_config;
1018     } categoryDefinitions packageDefinitions;
1019   in {
1020     # it can take a name of a package in packageDefinitions
1021     # and return the package!
1022     default = nixCatsBuilder defaultPackageName;
1023   });
1024 
1025 
1026   packages = nixpkgs.lib.genAttrs nixpkgs.lib.platforms.all (system: let
1027     # create our pkgs to pass to builder
1028     pkgs = import nixpkgs {
1029       inherit system;
1030       overlays = dependencyOverlays;
1031       config = extra_pkg_config;
1032     };
1033     # create our builder for our exports
1034     nixCatsBuilder = utils.baseBuilder luaPath {
1035       /* you can still use dependencyOverlays here and such as well to add */
1036       inherit pkgs; # <- but here we are just going to inherit the value.
1037     } categoryDefinitions packageDefinitions;
1038   in {
1039     # it can take a name of a package in packageDefinitions
1040     # and return the package!
1041     default = nixCatsBuilder defaultPackageName;
1042   });
1043 
1044 ---------------------------------------------------------------------------------------
1045 Flake Exports and Export options               nixCats.flake.outputs.exports
1046 
1047 They look something like this:
1048 
1049   # this first section is the outputs we
1050   # want to wrap with the ${system} variable
1051   utils.eachSystem nixpkgs.lib.platforms.all (system: let
1052     # this is the builder (see :h nixCats.flake.outputs.builder above):
1053     nixCatsBuilder = utils.baseBuilder luaPath {
1054       inherit nixpkgs system dependencyOverlays extra_pkg_config;
1055     } categoryDefinitions packageDefinitions;
1056     # then it takes our categoryDefinitions and packageDefinitions
1057 
1058     # then we build a package to serve as the default one by providing its name.
1059     defaultPackage = nixCatsBuilder defaultPackageName;
1060 
1061     # this is just for using utils in the following section such as pkgs.mkShell
1062     # The one used to build Neovim is resolved inside the builder
1063     # and is passed to our categoryDefinitions and packageDefinitions
1064     pkgs = import nixpkgs { inherit system; };
1065     # as you can see, "resolve pkgs" does not mean anything fancy.
1066     # however, with overlays and system variable,
1067     # sometimes you can get yourself in a loop when
1068     # doing more advanced things. So this flake takes care of that for you.
1069     # it will make sure pkgs is passed to the categoryDefinitions and packageDefinitions
1070   in
1071   {
1072     # these outputs will be wrapped with ${system} by utils.eachSystem
1073 
1074     # this will make a package out of each of the packageDefinitions defined above
1075     # and set the default package to the one passed in here.
1076     packages = utils.mkAllWithDefault defaultPackage;
1077 
1078     # choose your package for devShell
1079     # and add whatever else you want in it.
1080     devShells = {
1081       default = pkgs.mkShell {
1082         name = defaultPackageName;
1083         packages = [ defaultPackage ];
1084         inputsFrom = [ ];
1085         shellHook = ''
1086         '';
1087       };
1088     };
1089 
1090   }) // {
1091 
1092     # these outputs will be NOT wrapped with ${system}
1093 
1094     # now we can export some things that can be imported in other
1095     # flakes, WITHOUT needing to use a system variable to do it.
1096     # and update them into the rest of the outputs returned by the
1097     # eachSystem function.
1098 
1099     # this will make an overlay out of each of the packageDefinitions defined
1100     # and set the default overlay to the one named here.
1101     overlays = utils.makeOverlays luaPath {
1102       # we pass in the things to make a pkgs variable to build nvim with later
1103       inherit nixpkgs dependencyOverlays extra_pkg_config;
1104       # and also our categoryDefinitions
1105     } categoryDefinitions packageDefinitions defaultPackageName;
1106 
1107     # we export a NixOS module to allow configuration from configuration.nix
1108     # allows you to either inherit values from your main flake, or start fresh
1109     # It requires the system variable to build a package but not to build a module!
1110     nixosModules.default = utils.mkNixosModules {
1111       inherit dependencyOverlays luaPath defaultPackageName
1112         categoryDefinitions packageDefinitions nixpkgs;
1113     };
1114     # and the same for Home Manager
1115     homeModule = utils.mkHomeModules {
1116       inherit dependencyOverlays luaPath defaultPackageName
1117         categoryDefinitions packageDefinitions nixpkgs;
1118     };
1119     # and we export these so its super easy to grab them later.
1120     inherit utils;
1121     inherit (utils) templates;
1122   };
1123 
1124                                   nixCats.flake.outputs.utils
1125 
1126 The <utils> set exports all the functions used in creating the format in the
1127 templates, including the main builder!
1128 (see :h nixCats.flake.outputs.builder for builder explanation)
1129 
1130 In the interests of not repeating ourselves,
1131 a list of most functions exported in the <utils> set
1132 can be found here:
1133 https://nixcats.org/nixCats_utils.html
1134 
1135 Missing from that list however,
1136 is an explanation of the internal <n2l> library
1137 nixCats uses to create the nixCats Lua plugin!
1138 
1139 The library fully escapes all items passed to it,
1140 so usually you can't execute lua code in them.
1141 But you may still explicitly pass it lua code to execute at runtime
1142 by declaring them as inline lua types!
1143 
1144 An intricate explanation of the full set
1145 of features the <n2l> library contains are below.
1146 
1147 All other functions made available by
1148 the <utils> set are explained in the documentation
1149 at https://nixcats.org/nixCats_utils.html
1150 
1151                                   nixCats.flake.outputs.utils.n2l
1152 <n2l> This is the Nix to Lua library nixCats
1153 uses to create the nixCats Lua plugin
1154 You may wish to use some functions from it.
1155 
1156 The library is exported from the <utils> set as utils.n2l
1157 
1158 It contains <toLua> and <prettyLua> and <uglyLua> which convert Nix values to Lua.
1159 It also contains a <toUnpacked> which converts a nix list
1160 to comma separated lua values for function arguments.
1161 
1162 it contains a <member> function to determine if a value is a special "inline lua" type
1163 it contains a <typeof> function to determine which special "inline lua" type it is
1164 it contains a <resolve> function which knows how to resolve the types to a string of code
1165 it contains the <default_subtype> name as well.
1166 
1167 But of much more interest to you is the types you may declare.
1168 
1169 Everything being passed through settings, categories, and extra in packageDefinitions
1170 will be properly escaped. But this also means that
1171 you cannot write any Lua code there.
1172 
1173 Luckily, we have some types we can declare that will allow you to do this.
1174 
1175 To declare that an item is a Lua value rather than a hard coded one,
1176 you may choose one of these types. To do this, call its constructor!
1177 
1178 for example, types.inline-unsafe has 1 field, body.
1179 
1180 To declare one in our settings, categories, and extra sets, it would look
1181 something like this:
1182 
1183   categories = {
1184     somecat = utils.n2l.types.inline-unsafe.mk {body = "vim.fn.stdpath('data')"; }`
1185   }
1186 
1187 inline-safe is the default type, and it gets to define a shorthand form.
1188 
1189   categories = {
1190     somecat = utils.n2l.types.inline-safe.mk "vim.fn.stdpath('data')";`
1191   }
1192 
1193 These are all the types, each one has an associated mk
1194 function to create a value of that type,
1195 which accepts the fields listed here, defined with default values.
1196 
1197   # creates an inline Lua value in a way that cant break the table
1198   inline-safe = {
1199     default = (v: if v ? body then v else { body = v; });
1200     fields = { body = "nil"; };
1201     format = LI: "assert(loadstring(${luaEnclose "return ${LI.expr.body or LI.expr or "nil"}"}))()";
1202   };
1203   # iterpolates whatever string you provide into the table raw
1204   inline-unsafe = {
1205     fields = { body = "nil"; };
1206     format = LI: "${LI.expr.body or "nil"}";
1207   };
1208   # creates a function with args of the names given in args list
1209   # does so in a way where you cannot accidentally break the table
1210   function-safe = {
1211     fields = { body = "return nil"; args = []; };
1212     format = LI: 
1213       ''assert(loadstring(${luaEnclose ''return (function(${fixargs (LI.expr.args or [])}) ${LI.expr.body or "return nil"} end)''}))()'';
1214   };
1215   # creates a function with args of the names given in args list
1216   # interpolates the body segment raw, just like inline-unsafe, but in a function
1217   function-unsafe = {
1218     fields = { body = "return nil"; args = []; };
1219     format = LI: ''(function(${fixargs (LI.expr.args or [])}) ${LI.expr.body or "return nil"} end)'';
1220   };
1221   with-meta = {
1222     fields = {
1223       table = {}; # <- the table you are adding
1224       meta = {}; # <- the metatable you want to add to it (in Nix)
1225       newtable = null; # <- if you want to specify a different first arg to setmetatable
1226       tablevar = "tbl_in"; # <- varname to refer to the table, to avoid translating multiple times
1227     };
1228     format = LI: opts: let
1229       metaarg1 = if LI.expr.newtable or null == null then LI.expr.tablevar or "{}" else toLuaFull opts LI.expr.newtable;
1230       result = inline.types.function-unsafe.mk {
1231         args = [ (LI.expr.tablevar or "tbl_in") ];
1232         body = ''return setmetatable(${metaarg1}, ${toLuaFull opts LI.expr.meta})'';
1233       };
1234     in "${toLuaFull opts result}(${toLuaFull opts LI.expr.table})";
1235   };
1236 
1237 
1238 Some more useage examples:
1239 
1240   exampleSafeFunc = utils.n2l.types.function-safe.mk {
1241     args = [ "hello" ];
1242     body = /*lua*/ ''
1243       print(hello)
1244       return hi
1245     '';
1246   };
1247   exampleUnsafeFunc = utils.n2l.types.function-unsafe.mk {
1248     args = [ "hi" "hello" ];
1249     body = /*lua*/ ''
1250       print(hi)
1251       print(hello)
1252       return hi .. hello
1253     '';
1254   };
1255   };
1256   funcResults = {
1257     test1 = utils.n2l.types.inline-safe.mk ''${utils.n2l.resolve exampleSafeFunc}("Hello World!")'';
1258   };
1259   lua_table_with_meta = utils.n2l.types.with-meta.mk (let
1260     tablevar = "tbl_in";
1261   in {
1262     table = {
1263       this = "is a test table";
1264       inatesttable = "that will be translated to a Lua table with a metatable";
1265     };
1266     # to avoid translating the table multiple times,
1267     # define a variable name for it in Lua. Defaults to "tbl_in"
1268     inherit tablevar;
1269     meta = {
1270       # __call in Lua lets us also call it like a function
1271       __call = utils.n2l.types.function-unsafe.mk {
1272         args = [ "self" "..." ];
1273         body = ''
1274           print("This table is named ${tablevar}")
1275           return ${tablevar}.this
1276         '';
1277       };
1278     };
1279     # you can change it to set the metatable of
1280     # and return a different table instead.
1281     # sometimes done so that access always uses __index function
1282     newtable = null; # <- default val, sets metatable of tablevar
1283   });
1284 
1285 ---------------------------------------------------------------------------------------
1286 vim:tw=78:ts=8:ft=help:norl: