diff --git a/lib/maintainers.nix b/lib/maintainers.nix index 4c918db3..f534b767 100644 --- a/lib/maintainers.nix +++ b/lib/maintainers.nix @@ -143,4 +143,10 @@ name = "Jalil David Salamé Messina"; keys = [ { fingerprint = "7D6B 4D8F EBC5 7CBC 09AC 331F DA33 17E7 5BE9 485C"; } ]; }; + my7h3le = { + email = "mandate-word-dupe@duck.com"; + github = "my7h3le"; + githubId = 7899547; + name = "Tash"; + }; } diff --git a/plugins/pluginmanagers/lazy.nix b/plugins/pluginmanagers/lazy.nix index d041ff05..4b6b6901 100644 --- a/plugins/pluginmanagers/lazy.nix +++ b/plugins/pluginmanagers/lazy.nix @@ -1,42 +1,40 @@ +# TODO: add function (_, opts) docs { - lib, - helpers, config, + lib, pkgs, ... }: -with lib; let - cfg = config.plugins.lazy; - lazyPlugins = cfg.plugins; + inherit (lib.nixvim) + defaultNullOpts + keymaps + mkNullOrOption + mkNullOrLuaFn + mkNullOrStrLuaFnOr + ; + inherit (lib) types; - processPlugin = - plugin: - let - mkEntryFromDrv = - p: - if lib.isDerivation p then - { - name = "${lib.getName p}"; - path = p; - } - else - { - name = "${lib.getName p.pkg}"; - path = p.pkg; - }; - processDependencies = - if plugin ? dependencies && plugin.dependencies != null then - builtins.concatMap processPlugin plugin.dependencies - else - [ ]; - in - [ (mkEntryFromDrv plugin) ] ++ processDependencies; + # The regex used in this match function matches a string containing two + # segments separated by a single forward slash ('/'). Each segment is + # composed of one or more characters that are neither newlines ('\n') + # nor forward slashes ('/'). + # + # The pattern ensures that both segments must be non-empty and must not + # include line breaks or slashes within them. + isShortGitURL = x: lib.isStringLike x && builtins.match "[^\n/]+/[^\n/]+" (toString x) != null; - processedPlugins = builtins.concatLists (builtins.map processPlugin lazyPlugins); - lazyPath = pkgs.linkFarm "lazy-plugins" processedPlugins; + # The regex used in this match function matches any string that starts + # with either `https://` or `http://`. + isGitURL = x: lib.isStringLike x && builtins.match "https?://.*" (toString x) != null; + + inherit (config) isDocs; in -{ +lib.nixvim.plugins.mkNeovimPlugin { + name = "lazy"; + packPathName = "lazy.nvim"; + package = "lazy-nvim"; + # TODO: added 2025-04-06, remove after 25.05 imports = [ (lib.nixvim.mkRemovedPackageOptionModule { @@ -45,184 +43,486 @@ in }) ]; - options = { - plugins.lazy = { - enable = mkEnableOption "lazy.nvim"; + maintainers = with lib.maintainers; [ + MattSturgeon + my7h3le + ]; - package = lib.mkPackageOption pkgs [ - "vimPlugins" - "lazy-nvim" - ] { }; + settingsOptions = { + # TODO: check and maybe reword this description + git.url_format = defaultNullOpts.mkStr "https://github.com/%s.git" '' + The default url format that `lazy.nvim` expects short plugin urls to be + in. (See: upstream docs for `config.git.url_format` defined here + https://lazy.folke.io/configuration); + ''; - plugins = - with types; - let - pluginType = either package (submodule { - options = { - dir = helpers.mkNullOrOption str "A directory pointing to a local plugin"; + dev.fallback = defaultNullOpts.mkBool false '' + When false, `lazy.nvim` won't try to use git to fetch local plugins that + don't exist. + ''; - pkg = mkOption { - type = package; - description = "Vim plugin to install"; - }; - - name = helpers.mkNullOrOption str "Name of the plugin to install"; - - dev = helpers.defaultNullOpts.mkBool false '' - When true, a local plugin directory will be used instead. - See config.dev - ''; - - lazy = helpers.defaultNullOpts.mkBool true '' - When true, the plugin will only be loaded when needed. - Lazy-loaded plugins are automatically loaded when their Lua modules are required, - or when one of the lazy-loading handlers triggers - ''; - - enabled = helpers.defaultNullOpts.mkStrLuaFnOr types.bool "`true`" '' - When false then this plugin will not be included in the spec. (accepts fun():boolean) - ''; - - cond = helpers.defaultNullOpts.mkStrLuaFnOr types.bool "`true`" '' - When false, or if the function returns false, - then this plugin will not be loaded. Useful to disable some plugins in vscode, - or firenvim for example. (accepts fun(LazyPlugin):boolean) - ''; - - dependencies = helpers.mkNullOrOption (eitherRecursive str listOfPlugins) "Plugin dependencies"; - - init = helpers.mkNullOrLuaFn "init functions are always executed during startup"; - - config = helpers.mkNullOrStrLuaFnOr (types.enum [ true ]) '' - config is executed when the plugin loads. - The default implementation will automatically run require(MAIN).setup(opts). - Lazy uses several heuristics to determine the plugin's MAIN module automatically based on the plugin's name. - See also opts. To use the default implementation without opts set config to true. - ''; - - main = helpers.mkNullOrOption str '' - You can specify the main module to use for config() and opts(), - in case it can not be determined automatically. See config() - ''; - - submodules = helpers.defaultNullOpts.mkBool true '' - When false, git submodules will not be fetched. - Defaults to true - ''; - - event = - with lib.types; - helpers.mkNullOrOption (maybeRaw (either str (listOf str))) "Lazy-load on event. Events can be specified as BufEnter or with a pattern like BufEnter *.lua"; - - cmd = - with lib.types; - helpers.mkNullOrOption (maybeRaw (either str (listOf str))) "Lazy-load on command"; - - ft = - with lib.types; - helpers.mkNullOrOption (maybeRaw (either str (listOf str))) "Lazy-load on filetype"; - - keys = - with lib.types; - helpers.mkNullOrOption (maybeRaw (either str (listOf str))) "Lazy-load on key mapping"; - - module = helpers.mkNullOrOption (enum [ false ]) '' - Do not automatically load this Lua module when it's required somewhere - ''; - - priority = helpers.mkNullOrOption number '' - Only useful for start plugins (lazy=false) to force loading certain plugins first. - Default priority is 50. It's recommended to set this to a high number for colorschemes. - ''; - - optional = helpers.defaultNullOpts.mkBool false '' - When a spec is tagged optional, it will only be included in the final spec, - when the same plugin has been specified at least once somewhere else without optional. - This is mainly useful for Neovim distros, to allow setting options on plugins that may/may not be part - of the user's plugins - ''; - - opts = - with lib.types; - helpers.mkNullOrOption (maybeRaw (attrsOf anything)) '' - opts should be a table (will be merged with parent specs), - return a table (replaces parent specs) or should change a table. - The table will be passed to the Plugin.config() function. - Setting this value will imply Plugin.config() - ''; - }; - }); - - listOfPlugins = types.listOf pluginType; - in - mkOption { - type = listOfPlugins; - default = [ ]; - description = "List of plugins"; - }; - }; + install.missing = defaultNullOpts.mkBool false '' + When false, `lazy.nvim` won't try to install missing plugins on startup. + Setting this to true won't increase startup time. + ''; }; - config = mkIf cfg.enable { - extraPlugins = [ cfg.package ]; + extraOptions = + with types; + let + shortGitURL = lib.mkOptionType { + name = "shorGitURL"; + description = "a short git url of the form `owner/repo`"; + descriptionClass = "noun"; + check = isShortGitURL; + merge = lib.mergeEqualOption; + }; - dependencies.git.enable = lib.mkDefault true; + gitURL = lib.mkOptionType { + name = "gitURL"; + description = "a git url"; + descriptionClass = "noun"; + check = isGitURL; + merge = lib.mergeEqualOption; + }; - extraConfigLua = - let - pluginToLua = - plugin: - if isDerivation plugin then - { dir = "${lazyPath}/${lib.getName plugin}"; } - else - { - "__unkeyed" = plugin.name; + lazyPluginSourceType = oneOf [ + package + path + shortGitURL + gitURL + ]; - inherit (plugin) - cmd - cond - config - dev - enabled - event - ft - init - keys - lazy - main - module - name - optional - opts - priority - submodules - ; + lazyPluginType = coercedTo lazyPluginSourceType (source: { inherit source; }) ( + submodule ( + { config, ... }: - dependencies = helpers.ifNonNull' plugin.dependencies ( - if isList plugin.dependencies then (pluginListToLua plugin.dependencies) else plugin.dependencies - ); + { + freeformType = attrsOf anything; + options = { + source = mkNullOrOption lazyPluginSourceType '' + The `source` option i.e. `plugins.lazy.plugins..source` is just + a convenience nixvim option that makes it easier to specify a plugin + source whether it be a: - dir = - if plugin ? dir && plugin.dir != null then plugin.dir else "${lazyPath}/${lib.getName plugin.pkg}"; + - nix package + - directory path + - git url + - short git url of the form `owner/repo` + + and the `source` option itself is not a part of the upstream + `lazy.nvim` plugin spec (See: https://lazy.folke.io/spec). + + As a result the values given to `source` need to be mapped to + properties in the upstream `lazy.nvim` plugin spec i.e. + ([1]|dir|url). After which the `source` attribute itself will + be stripped from the final lua config. + ``` + ''; + + # TODO: rework 3rd paragraph of this, make sure you add the fact + # that with custom name it has to be defined somewhere else in + # the list + name = mkNullOrOption str '' + A custom name for the plugin used for the local plugin + directory and as the display name. By default nixvim will set + a default value for this depending on what was specified to + `plugins.lazy.plugins..source`, namely if a nix package + was given to `plugins.lazy.plugins..source` then name + will default to the nix package's name, and if a git url or a + short git url was specified, then name will default to the base + name of that url. + + It is also worth mentioning that a plugin can have the option + `plugins.lazy.plugins..name` defined but not have + `plugins.lazy.plugins..source` defined. + + In these cases, a custom `name` can be used instead of `source` + and the plugin spec options given will be applied or merged with + the original plugin definition. This is particularly useful for + plugins that bundle multiple modules (e.g. mini-nvim, which + includes mini-ai, mini-trailspace, etc.), where you need to + modify options for individual modules without affecting the + entire bundle. + ''; + + dev = defaultNullOpts.mkBool false '' + When true, `lazy.nvim` will look for this plugin in the local + plugin directory defined at `plugin.lazy.settings.dev.path`. + ''; + + lazy = defaultNullOpts.mkBool true '' + When true, the plugin will only be loaded when needed. + + Lazy-loaded plugins are automatically loaded when their Lua + modules are required, or when one of the lazy-loading + handlers are triggered. + + You can define which triggers load this plugin using + `plugins.lazy.plugins..[event|cmd|ft|keys]`. + ''; + + enabled = defaultNullOpts.mkStrLuaFnOr bool true '' + When false or if a function that returns false is defined + then this plugin will not be included in the final spec. The + plugin will also be uninstalled when true if the plugin is an + out of tree non nix package plugin. (accepts fun():boolean). + ''; + + cond = defaultNullOpts.mkStrLuaFnOr bool true '' + Behaves the same as `plugins.lazy.plugins..enabled`, + but won't uninstall the plugin when the condition is false. + Useful to disable some plugins in vscode, or firenvim for + example. + + Note: Since out of tree non nix package plugins are only ever + uninstalled by `lazy.nvim`, this option as far as nix package + plugins are concerned, only serves the same purpose as + `plugins.lazy.plugins..enabled`. + ''; + + # WARNING: Be very careful if changing the type of + # `dependencies`. Choosing the wrong type may cause a stack + # overflow due to infinite recursion, and it's very possible that + # the test cases won't catch this problem. To be safe, perform + # thorough manual testing if you do change the type of + # `dependencies`. + dependencies = + let + lazyPluginDependenciesType = + if isDocs then + # Use a stub type for documentation purposes We don't + # need to repeat all the plugin-type sub-options again in + # the docs It'd also be infinitely recursive + lib.mkOptionType { + name = "pluginDependencies"; + description = "plugin submodule"; + descriptionClass = "noun"; + check = throw "should not be used"; + merge = throw "should not be used"; + } + else + # NOTE: use attrsOf for the LHS, because coercedTo only supports submodules on the RHS + coercedTo (either (attrsOf anything) lazyPluginSourceType) lib.toList (listOf lazyPluginType); + in + mkNullOrOption lazyPluginDependenciesType '' + In terms of setting values to this option it is effectively + the same as `plugins.lazy.plugins`, with the following + additions in terms of what it can be: + + - It can also be single string such as for a custom plugin + name e.g. `dependencies = "nvim-treesitter";` + + + If it is just a custom name however, then the plugin spec + must be defined somewhere else in the list given to + `plugins.lazy.plugins`. For example: + + ```Nix + { + plugins.lazy.plugins = with pkgs.vimPlugins; [ + { + + # Only a custom name was given to + # `plugins.lazy.plugins..dependencies`, + # therefore a plugin spec with this name must be + # defined somewhere else in the list given to + # `plugins.lazy.plugins`. + source = nvim-treesitter-textobjects; + dependencies = "nvim-treesitter"; + } + + # We define the plugin spec with name "nvim-treesitter" + # here: + { + source = nvim-treesitter; + + # Note: By default if a nix package is given to + # `plugins.lazy.plugins..source`, then the + # `name` option will have have a default value of + # that nix package's name. So in this example the + # custom name of "nvim-treesitter" doesn't need to + # be explicitly set here as the nix package + # `pkgs.vimPlugins.nvim-treesitter` name attribute + # is already "nvim-treesitter". + name = "nvim-treesitter"; + + opts = { + highlight = { + enable = true; + }; + ensure_installed = [ + "vim" + "regex" + "lua" + "bash" + "markdown" + "angular" + "markdown_inline" + "hyprlang" + ]; + parser_install_dir.__raw = "vim.fs.joinpath(vim.fn.stdpath('data'), 'site')"; + }; + } + ]; + } + ``` + + - A single nix plugin package (e.g. `dependencies = pkgs.vimPlugins.nvim-treesitter;`) + + Outside of these additions, what it can be set to is + effectively the same as `plugins.lazy.plugins` i.e. A list of + nix plugin packages and or attribute sets denoting plugin + specs that should be loaded, and loaded before the current + plugin loads. Dependencies are always lazy-loaded unless + specified otherwise. When specifying a name, make sure the + plugin spec has been defined somewhere else. (See: + https://lazy.folke.io/spec). + ''; + + init = mkNullOrLuaFn '' + Functions that are always executed during startup. Mostly + useful for setting vim.g.* configuration used by Vim plugins + startup. + ''; + + config = mkNullOrStrLuaFnOr (enum [ true ]) '' + A lua function with signature `fun(LazyPlugin, opts:table)` + that gets executed when the plugin loads. It can also just be + a `true` boolean. + + The default implementation will automatically run + `require(MAIN).setup(opts)` if + `plugins.lazy.plugins..opts` is set or if `config` + itself is set to `true`. Lazy uses several heuristics to + determine the plugin's MAIN module automatically based on the + plugin's name. (`plugins.lazy.plugins..opts` is the + recommend way to configure plugins). + ''; + + main = mkNullOrOption str '' + You can specify the main module to use for + `plugins.lazy.plugins..config` and + `plugins.lazy.plugins..opts`, in case it can not be + determined automatically. + + See `plugins.lazy.plugins..config`. + ''; + + submodules = defaultNullOpts.mkBool true '' + When `false`, git submodules will not be fetched. Defaults to `true` + ''; + + event = mkNullOrOption (maybeRaw (either str (listOf str))) '' + Lazy-load on event. Events can be specified as `BufEnter`, a + pattern like `BufEnter *.lua` or a list of events `event = [ + "BufRead" "BufEnter" ];`. It can also be a lua function of + signature `fun(self:LazyPlugin, event:string[])` that returns a + list of strings. + + See https://neovim.io/doc/user/autocmd.html for a more info neovim events. + Also see upstream `lazy.nvim` docs at https://lazy.folke.io/spec + ''; + + cmd = mkNullOrOption (maybeRaw (either str (listOf str))) '' + Lazy-load on command. Commands can be specified as a single + string like `StartupTime` or a list of strings to lazy load the + plugin on any given command. This can also be a lua function that + returns a list of strings. + + Example: + + ```Nix + { + plugins.lazy.plugins = with pkgs.vimPlugins; [ + { + source = vim-startuptime; + # Lazy load plugin when `StartupTime` command is invoked. + cmd = "StartupTime"; + } + ]; + } + ``` + ''; + + ft = mkNullOrOption (maybeRaw (either str (listOf str))) '' + Lazy-load plugin only on a given filetype/filetypes e.g.: + + ```Nix + plugins.lazy.plugins = with pkgs.vimPlugins; [ + { + source = neorg; + # Only load plugin on "norg" filetyes + # Note: this can also be a list as well (i.e. `ft = [ "norg" ];`) + ft = "norg"; + opts = { + load."['core.defaults']" = [ ]; + }; + } + ]; + ``` + + Can also be a lua function that returns a list of strings, that + denote filetyes. Example: + + ```Nix + plugins.lazy.plugins = with pkgs.vimPlugins; [ + { + source = neorg; + # Can also be a function that returns a list of filetypes + ft = "function() return { "norg" } end" + opts = { + load."['core.defaults']" = [ ]; + }; + } + ]; + ``` + ''; + + # TODO: add better description here + keys = mkNullOrOption (listOf ( + keymaps.mkMapOptionSubmodule { + defaults = { + mode = "n"; + }; + # HACK: with how `mkMapOptionSubmodule` is currently + # defined, mode will keep being set to default value + # denoted by `defaults.mode`, and the user can not override + # it without this workaround. + extraOptions = { + mode = keymaps.mkModeOption "n"; + action = mkNullOrOption (maybeRaw str) '' + The action to execute. + ''; + ft = mkNullOrOption (either (maybeRaw str) (listOf (maybeRaw str))) '' + Make the keybind trigger for only certain file type/s. + ''; + }; + } + )) "Lazy-load on key mapping"; + + module = mkNullOrOption (enum [ false ]) '' + Do not automatically load this Lua module when it's required somewhere. + ''; + + priority = defaultNullOpts.mkInt 50 '' + Only useful for start plugins i.e. + `plugins.lazy.plugins..lazy = false` to force loading + certain plugins first. Default priority is 50. It's + recommended to set this to a high number for colorschemes. + ''; + + optional = defaultNullOpts.mkBool false '' + Optional specs are only included in the final configuration + if the corresponding plugin is also specified as a required + (non-optional) plugin elsewhere. This feature is + particularly helpful for Neovim distributions, allowing + them to pre-configure settings for plugins that users may + or may not have installed. + ''; + + opts = defaultNullOpts.mkAttrsOf anything { } '' + The opts value can be one of the following: + + - An attribute set: The equivalent of this in lua would be a + table. This options defined in this attribute set will be + merged with any existing configuration settings from the parent + specification of the plugin. + + - A function that returns a table: The returned table will + completely replace any existing configuration settings from + the plugin's parent specifications. + + - A function that modifies a table: This function will + receive the existing configuration table as an argument and + can modify it directly. + + In all cases, the resulting configuration table will be passed + to the `plugins.lazy.plugins..config` function. Setting + the opts value automatically implies that the + `plugins.lazy.plugins..config` function will be called. + (See: https://lazy.folke.io/spec#spec-setup) + ''; }; - pluginListToLua = map pluginToLua; - - plugins = pluginListToLua cfg.plugins; - - packedPlugins = if length plugins == 1 then head plugins else plugins; - in - mkIf (cfg.plugins != [ ]) '' - require('lazy').setup( - { - dev = { - path = "${lazyPath}", - patterns = {"."}, - fallback = false - }, - spec = ${lib.nixvim.toLuaObject packedPlugins} + # Set the name of a plugin by default. This is mostly for + # convenience as it avoids long nix store paths be shown as the + # display names when running `:Lazy`. + config.name = lib.mkIf (config.source != null) ( + if (lib.isDerivation config.source) then + lib.mkDefault "${lib.getName config.source}" + else + lib.mkDefault "${builtins.baseNameOf config.source}" + ); } ) - ''; + ); + + lazyPluginsListType = listOf lazyPluginType; + in + { + luarocksPackage = lib.mkPackageOption pkgs "luarocks" { nullable = true; }; + + plugins = lib.mkOption { + type = lazyPluginsListType; + default = [ ]; + description = "List of plugins"; + }; + }; + + extraConfig = cfg: { + dependencies.git.enable = lib.mkDefault true; + + extraPackages = [ + cfg.luarocksPackage + ]; + plugins.lazy.settings.spec = + let + convertToLazyKeyMappingType = + km: + { + __unkeyed-1 = km.key; + } + // lib.optionalAttrs (lib.hasAttr "action" km) { __unkeyed-2 = km.action; } + // lib.optionalAttrs (lib.hasAttr "mode" km) { inherit (km) mode; } + // lib.optionalAttrs (lib.hasAttr "ft" km) { inherit (km) ft; } + // lib.removeAttrs km [ + "action" + "mode" + "ft" + ]; + + pluginToSpec = + plugin: + lib.concatMapAttrs ( + key: value: + if key == "source" && value != null then + { + dir = if (lib.isDerivation value || lib.isPath value) then "${value}" else null; + __unkeyed = if (isShortGitURL value) then value else null; + url = if (isGitURL value) then value else null; + } + else if (key == "name" && value != null) && ((plugin.source or null) == null) then + { __unkeyed = value; } + else if key == "dependencies" && value != null then + { dependencies = map pluginToSpec value; } + # If the user explicitly sets the 'dir' option, use the provided + # value instead of an extrapolated default. + else if (key == "dir" && value != null) then + { dir = value; } + # If the user explicitly sets the 'url' option, use the provided + # value instead of an extrapolated default. + else if (key == "url" && value != null) then + { url = value; } + # If the 'keys' option is given, we need to explicitly convert that into a form that `lazy.nvim` expects. + else if (key == "keys" && value != null) then + { keys = map convertToLazyKeyMappingType value; } + # Preserve all other key value pair mappings, this also handles + # freeform options. + else + { "${key}" = value; } + ) plugin; + in + map pluginToSpec cfg.plugins; }; } diff --git a/tests/test-sources/plugins/pluginmanagers/lazy.nix b/tests/test-sources/plugins/pluginmanagers/lazy.nix index 663a74cb..6872e532 100644 --- a/tests/test-sources/plugins/pluginmanagers/lazy.nix +++ b/tests/test-sources/plugins/pluginmanagers/lazy.nix @@ -1,20 +1,82 @@ { pkgs, ... }: + +# Note: do not use `plenary-nvim` or any plugin that is a `rockspec` for tests, +# this is because `lazy.nvim` by default uses the luarocks package manager to +# process rockspecs. It might be possible to use a rockspec in a test if the +# rockspec itself does not depend on any other rockspecs but this has not been +# tested (See: +# https://github.com/nix-community/nixvim/pull/2082#discussion_r1746585453). +# +# Also the plugins and dependency combinations used in the tests are +# arbitrary. + { # Empty configuration empty = { plugins.lazy.enable = true; }; - test = { + no-packages = { + dependencies.git.enable = false; + plugins.lazy.enable = true; + }; + + nix-package-plugins = { + plugins.lazy = { + enable = true; + + plugins = with pkgs.vimPlugins; [ + # A plugin can be just a nix package + vim-closer + + # A plugin can also be an attribute set with `source` set to a nix + # package. + { source = trouble-nvim; } + ]; + }; + }; + + out-of-tree-plugins = { + # Don't run neovim for this test, as it's purely to test module evaluation. + test.runNvim = false; + plugins.lazy = { + enable = true; + + plugins = [ + # `source` can also be a short git url of the form `owner/repo` + { source = "echasnovski/mini.align"; } + + # `source` can also be a full git url with `http://` or `https://` + { + source = "https://github.com/nvim-telescope/telescope.nvim"; + enabled = true; + version = false; + } + { + source = "http://github.com/norcalli/nvim-colorizer.lua"; + enabled = true; + version = false; + } + ]; + }; + }; + + general-tests = { plugins.lazy = with pkgs.vimPlugins; { enable = true; plugins = [ - vim-closer + # Test freeform + { + source = trouble-nvim; + # The below is not actually a property in the `lazy.nvim` plugin spec + # but is purely to test freeform capabilities of the `lazyPluginType`. + blah = "test"; + } # Load on specific commands { - pkg = vim-dispatch; + source = vim-dispatch; optional = true; cmd = [ "Dispatch" @@ -26,13 +88,46 @@ # Load on an autocommand event { - pkg = vim-matchup; + source = vim-matchup; event = "VimEnter"; } + # Load on key mapping + { + source = neo-tree-nvim; + keys = [ + { + action = "make"; + key = ""; + mode = [ + "v" + "n" + ]; + ft = [ + "*.txt" + "*.cpp" + ]; + options = { + silent = true; + }; + } + ]; + } + + # Load on key mapping without specifying action + { + source = markdown-preview-nvim; + cmd = "MarkdownPreview"; + keys = [ + { + key = ""; + } + ]; + } + # Load on a combination of conditions: specific filetypes or commands { - pkg = ale; + source = ale; name = "w0rp/ale"; ft = [ "sh" @@ -50,48 +145,213 @@ cmd = "ALEEnable"; } - # Plugins can have dependencies on other plugins - { - pkg = completion-nvim; - optional = true; - dependencies = [ - { - pkg = vim-vsnip; - optional = true; - } - { - pkg = vim-vsnip-integ; - optional = true; - } - ]; - } - - # Plugins can have post-install/update hooks - { - pkg = markdown-preview-nvim; - cmd = "MarkdownPreview"; - } - # Post-install/update hook with neovim command { - pkg = nvim-treesitter; + source = nvim-treesitter; opts = { ensure_installed = { }; }; } - - # Use dependency and run lua function after load - { - pkg = gitsigns-nvim; - dependencies = [ plenary-nvim ]; - config = ''function() require("gitsigns").setup() end''; - } ]; }; }; - no-packages = { - dependencies.git.enable = false; - plugins.lazy.enable = true; + nix-pkg-plugin-dependencies = { + plugins.lazy = { + enable = true; + plugins = with pkgs.vimPlugins; [ + # A plugin spec can just consist of a `name` so long as a nix package + # with the same name is defined else where in the + # `plugins.lazy.plugins` list. + { name = "nvim-treesitter"; } + nvim-treesitter + + # A plugin spec can also just consist of a `name` so long as another + # plugin spec that references that same name is defined elsewhere in + # the `plugins.lazy.plugins`. This other plugin spec must also have a + # source `attribute` that appropriately references a nix package, full + # git url or short git url. + { name = "neovim-org-mode"; } + { + name = "neovim-org-mode"; + source = neorg; + } + + # Plugins can have dependencies on other plugins + { + source = completion-nvim; + optional = true; + dependencies = [ + { + source = vim-vsnip; + optional = true; + } + { + source = vim-vsnip-integ; + optional = true; + } + ]; + } + + # Use dependency and run lua function after load + { + source = nvim-colorizer-lua; + dependencies = [ nvim-cursorline ]; + config = '' + function() + require("nvim-cursorline").setup{} + end ''; + } + + # Dependencies can be a single package + { + source = LazyVim; + dependencies = trouble-nvim; + } + + # Dependencies can be multiple packages + { + source = nvim-cmp; + dependencies = [ + cmp-cmdline + cmp-vsnip + ]; + } + ]; + }; + }; + + out-of-tree-plugin-dependencies = { + # Don't run neovim for this test, as it's purely to test module evaluation. + test.runNvim = false; + plugins.lazy = { + enable = true; + plugins = [ + # A single plugin url's can be passed by itself to `dependencies` + { + source = "kristijanhusak/vim-dadbod-completion"; + dependencies = "kristijanhusak/vim-dadbod"; + } + # An out of tree plugin can have several dependencies + { + source = "hrsh7th/nvim-cmp"; + version = false; + event = "InsertEnter"; + dependencies = [ + "hrsh7th/cmp-nvim-lsp" + "hrsh7th/cmp-buffer" + "hrsh7th/cmp-path" + ]; + } + # Full git urls can also be used to dependencies + { + source = "https://github.com/mfussenegger/nvim-dap"; + dependencies = [ + "https://github.com/folke/which-key.nvim" + "https://github.com/mfussenegger/nvim-jdtls" + ]; + } + ]; + }; + }; + + disabling-plugins = { + plugins.lazy = with pkgs.vimPlugins; { + enable = true; + plugins = [ + # Enable and then later disable a plugin using it's custom name. + { + name = "mini.ai"; + source = mini-nvim; + enabled = true; + } + { + name = "mini.ai"; + enabled = false; + } + + # Enable and then later disable a plugin using `source`. + { + source = vim-closer; + enabled = true; + } + { + source = vim-closer; + enabled = false; + } + + # Enable plugin using `source` and then later disable it using the nix + # package's default name. + { + source = vim-dispatch; + enabled = true; + } + { + name = "vim-dispatch"; + source = vim-dispatch; + enabled = true; + } + ]; + }; + }; + + local-directory-plugins = { + plugins.lazy = + with pkgs.vimPlugins; + let + inherit (pkgs) lib; + mkEntryFromDrv = drv: { + name = "${lib.getName drv}"; + path = drv; + }; + + # Symlink a bunch of test packages to a path in the nix store + devPath = pkgs.linkFarm "dev-test-plugins" ( + map mkEntryFromDrv [ + nui-nvim + vim-vsnip-integ + vim-vsnip + completion-nvim + ] + ); + in + { + enable = true; + settings = { + dev = { + # Use `devPath` to simulate a local plugin directory + path = "${devPath}"; + patterns = [ "." ]; + fallback = false; + }; + }; + + plugins = [ + # Use local plugin that resides in path specified in `devPath` i.e. + # `plugins.lazy.settings.dev.path` (See: https://lazy.folke.io/spec) + { + dev = true; + name = "nui.nvim"; + } + # local plugins can have dependencies on other plugins + { + # Note: the name of the plugin has to correspond to the name of a + # plugin subdirectory under the directory denoted by + # `plugins.lazy.settings.dev.path` + name = "completion-nvim"; + dev = true; + dependencies = [ + { + dev = true; + name = "vim-vsnip"; + } + { + name = "vim-vsnip-integ"; + dev = true; + } + ]; + } + ]; + }; }; }