From e89d919e4da844137b060c7bc7dc930c7e098d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=A9tan=20Lepage?= <33058747+GaetanLepage@users.noreply.github.com> Date: Sun, 12 Mar 2023 18:23:23 +0100 Subject: [PATCH] plugins/packer: refactoring + fixes + tests (#243) --- plugins/pluginmanagers/packer.nix | 252 +++++++++++++++++++++++------- tests/plugins/packer.nix | 121 ++++++++++++++ 2 files changed, 314 insertions(+), 59 deletions(-) create mode 100644 tests/plugins/packer.nix diff --git a/plugins/pluginmanagers/packer.nix b/plugins/pluginmanagers/packer.nix index c132f6d0..e9835814 100644 --- a/plugins/pluginmanagers/packer.nix +++ b/plugins/pluginmanagers/packer.nix @@ -12,53 +12,122 @@ in { plugins.packer = { enable = mkEnableOption "packer.nvim"; - plugins = mkOption { - type = types.listOf (types.oneOf [ - types.str - (with types; let - mkOpt = type: desc: - mkOption { - type = nullOr type; - default = null; - description = desc; + plugins = with types; let + pluginType = + either + str + (submodule { + options = { + name = mkOption { + type = str; + description = "Name of the plugin to install"; }; - function = attrsOf str; - in - types.submodule { - options = { - name = mkOption { - type = str; - description = "Name of the plugin to install"; - }; - disable = mkOpt bool "Mark plugin as inactive"; - as = mkOpt bool "Specifies an alias under which to install the plugin"; - installer = mkOpt function "A custom installer"; - updater = mkOpt function "A custom updater"; - after = mkOpt (oneOf [str (listOf any)]) "Plugins to load after this plugin"; - rtp = mkOpt str "Specifies a subdirectory of the plugin to add to runtimepath"; - opt = mkOpt str "Marks a plugin as optional"; - branch = mkOpt str "Git branch to use"; - tag = mkOpt str "Git tag to use"; - commit = mkOpt str "Git commit to use"; - lock = mkOpt bool "Skip this plugin in updates"; - run = mkOpt (oneOf [str function]) "Post-install hook"; - requires = mkOpt (oneOf [str (listOf any)]) "Plugin dependencies"; - rocks = mkOpt (oneOf [str (listOf any)]) "Luarocks dependencies"; - config = mkOpt (oneOf [str function]) "Code to run after this plugin is loaded"; - setup = mkOpt (oneOf [str function]) "Code to be run before this plugin is loaded"; - cmd = mkOpt (oneOf [str (listOf str)]) "Commands which load this plugin"; - ft = mkOpt (oneOf [str (listOf str)]) "Filetypes which load this plugin"; - keys = mkOpt (oneOf [str (listOf str)]) "Keymaps which load this plugin"; - event = mkOpt (oneOf [str (listOf str)]) "Autocommand events which load this plugin"; - fn = mkOpt (oneOf [str (listOf str)]) "Functions which load this plugin"; - cond = mkOpt (oneOf [str function (listOf (oneOf [str function]))]) "Conditional test to load this plugin"; - module = mkOpt (oneOf [str (listOf str)]) "Patterns of module names which load this plugin"; - }; - }) - ]); + disable = helpers.mkNullOrOption bool "Mark plugin as inactive"; + + as = + helpers.mkNullOrOption str + "Specifies an alias under which to install the plugin"; + + installer = helpers.mkNullOrOption str "A custom installer"; + + updater = helpers.mkNullOrOption str "A custom updater"; + + after = + helpers.mkNullOrOption (either str (listOf str)) + "Plugins to load after this plugin"; + + rtp = + helpers.mkNullOrOption str + "Specifies a subdirectory of the plugin to add to runtimepath"; + + opt = helpers.mkNullOrOption bool "Marks a plugin as optional"; + + branch = helpers.mkNullOrOption str "Git branch to use"; + + tag = helpers.mkNullOrOption str "Git tag to use"; + + commit = helpers.mkNullOrOption str "Git commit to use"; + + lock = helpers.mkNullOrOption bool "Skip this plugin in updates"; + + run = + helpers.mkNullOrOption + (oneOf [ + str + helpers.rawType + (listOf (either str helpers.rawType)) + ]) + "Post-install hook"; + + requires = helpers.mkNullOrOption (either str listOfPlugins) "Plugin dependencies"; + + rocks = + helpers.mkNullOrOption (either str (listOf (either str attrs))) + "Luarocks dependencies"; + + config = + helpers.mkNullOrOption (either str helpers.rawType) + "Code to run after this plugin is loaded"; + + setup = + helpers.mkNullOrOption (either str helpers.rawType) + "Code to be run before this plugin is loaded"; + + cmd = + helpers.mkNullOrOption (either str (listOf str)) + "Commands which load this plugin"; + + ft = + helpers.mkNullOrOption (either str (listOf str)) + "Filetypes which load this plugin"; + + keys = + helpers.mkNullOrOption (either str (listOf str)) + "Keymaps which load this plugin"; + + event = + helpers.mkNullOrOption (either str (listOf str)) + "Autocommand events which load this plugin"; + + fn = + helpers.mkNullOrOption (either str (listOf str)) + "Functions which load this plugin"; + + cond = + helpers.mkNullOrOption + (oneOf [ + str + helpers.rawType + (listOf (either str helpers.rawType)) + ]) + "Conditional test to load this plugin"; + + module = + helpers.mkNullOrOption (either str (listOf str)) + "Patterns of module names which load this plugin"; + }; + }); + + listOfPlugins = types.listOf pluginType; + in + mkOption { + type = listOfPlugins; + default = []; + description = "List of plugins"; + }; + + rockPlugins = mkOption { + type = with types; listOf (either str attrs); + description = "List of lua rock plugins"; default = []; - description = "List of plugins"; + example = '' + [ + "penlight" + "lua-resty-http" + "lpeg" + ] + ''; }; }; }; @@ -68,29 +137,94 @@ in { extraPackages = [pkgs.git]; extraConfigLua = let - plugins = - map - (plugin: - if isAttrs plugin - then - mapAttrs' (k: v: { - name = - if k == "name" - then "@" - else k; - value = v; - }) - plugin - else plugin) - cfg.plugins; + luaRockPluginToLua = luaRockPlugin: + if isAttrs luaRockPlugin + then + mapAttrs' + (k: v: { + name = + if k == "name" + then "@" + else k; + value = v; + }) + luaRockPlugin + else luaRockPlugin; + luaRockListToLua = map luaRockPluginToLua; + + pluginToLua = plugin: + if isAttrs plugin + then { + "@" = plugin.name; + + inherit (plugin) disable as; + + installer = + helpers.ifNonNull' plugin.installer + (helpers.mkRaw plugin.installer); + + updater = + helpers.ifNonNull' plugin.updater + (helpers.mkRaw plugin.updater); + + inherit + (plugin) + after + rtp + opt + branch + tag + commit + lock + run + ; + + requires = + helpers.ifNonNull' plugin.requires + ( + if isList plugin.requires + then (pluginListToLua plugin.requires) + else plugin.requires + ); + + rocks = + helpers.ifNonNull' plugin.rocks + ( + if isList plugin.rocks + then luaRockListToLua plugin.rocks + else plugin.rocks + ); + + inherit + (plugin) + config + setup + cmd + ft + keys + event + fn + cond + module + ; + } + else plugin; + + pluginListToLua = map pluginToLua; + + plugins = pluginListToLua cfg.plugins; + packedPlugins = if length plugins == 1 then head plugins else plugins; + + luaRockPlugins = luaRockListToLua cfg.rockPlugins; in mkIf (cfg.plugins != []) '' require('packer').startup(function() use ${helpers.toLuaObject packedPlugins} + use_rocks ${helpers.toLuaObject luaRockPlugins} end) ''; }; diff --git a/tests/plugins/packer.nix b/tests/plugins/packer.nix new file mode 100644 index 00000000..7e38d381 --- /dev/null +++ b/tests/plugins/packer.nix @@ -0,0 +1,121 @@ +{ + # Empty configuration + empty = { + plugins.packer.enable = true; + }; + + test = { + plugins.packer = { + enable = true; + + plugins = [ + # Packer can manage itself + "wbthomason/packer.nvim" + + # Simple plugins can be specified as strings + "rstacruz/vim-closer" + + # Lazy loading: + # Load on specific commands + { + name = "tpope/vim-dispatch"; + opt = true; + cmd = ["Dispatch" "Make" "Focus" "Start"]; + } + + # Load on an autocommand event + { + name = "andymass/vim-matchup"; + event = "VimEnter"; + } + + # Load on a combination of conditions: specific filetypes or commands + # Also run code after load (see the "config" key) + { + name = "w0rp/ale"; + ft = ["sh" "zsh" "bash" "c" "cpp" "cmake" "html" "markdown" "racket" "vim" "tex"]; + cmd = "ALEEnable"; + config = "vim.cmd[[ALEEnable]]"; + } + + # Plugins can have dependencies on other plugins + { + name = "haorenW1025/completion-nvim"; + opt = true; + requires = [ + { + name = "hrsh7th/vim-vsnip"; + opt = true; + } + { + name = "hrsh7th/vim-vsnip-integ"; + opt = true; + } + ]; + } + + # Plugins can also depend on rocks from luarocks.org: + { + name = "my/supercoolplugin"; + rocks = [ + "lpeg" + { + name = "lua-cjson"; + version = "2.1.0"; + } + ]; + } + + # Local plugins can be included + "~/projects/personal/hover.nvim" + + # Plugins can have post-install/update hooks + { + name = "iamcco/markdown-preview.nvim"; + run = "cd app && yarn install"; + cmd = "MarkdownPreview"; + } + + # Post-install/update hook with neovim command + { + name = "nvim-treesitter/nvim-treesitter"; + run = ":TSUpdate"; + } + + # Post-install/update hook with call of vimscript function with argument + { + name = "glacambre/firenvim"; + run.__raw = ''function() vim.fn["firenvim#install"](0) end''; + } + + # Use specific branch, dependency and run lua file after load + { + name = "glepnir/galaxyline.nvim"; + branch = "main"; + config.__raw = ''function() require"statusline" end''; + requires = ["kyazdani42/nvim-web-devicons"]; + } + + # Use dependency and run lua function after load + { + name = "lewis6991/gitsigns.nvim"; + requires = ["nvim-lua/plenary.nvim"]; + config.__raw = ''function() require("gitsigns").setup() end''; + } + + # You can alias plugin names + { + name = "dracula/vim"; + as = "dracula"; + } + ]; + + # You can specify rocks in isolation + rockPlugins = [ + "penlight" + "lua-resty-http" + "lpeg" + ]; + }; + }; +}