Skip to content

Commit

Permalink
feat: create singleton events/commands/keymaps for load handlers
Browse files Browse the repository at this point in the history
Implementing the idea @lewis6991 proposed for handling multiple loads on
the same command/keymap/event added by separate calls to `add`. Changes
the loaders to keep a table of plugins associated with a given load
trigger and only create new events/keymaps/commands for new triggers,
otherwise simply appending to the set of plugins to be loaded on the
given trigger.

One note: we may need to make loaders delete plugins from these lists
after load, to handle cases like:
- add(event, plugins_1)
- event happens, plugins_1 loaded
- add(event, plugins_2)
- event happens, without deleting plugins_1 gets loaded again

I don't believe that this is a potential bug introduced by this
change---it could've happened with the more naive handlers as well
  • Loading branch information
wbthomason authored and lewis6991 committed Dec 6, 2022
1 parent 5cb06da commit c89092c
Show file tree
Hide file tree
Showing 14 changed files with 96 additions and 176 deletions.
22 changes: 11 additions & 11 deletions lua/packer/handlers/cmd.lua

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 11 additions & 14 deletions lua/packer/handlers/event.lua

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 14 additions & 17 deletions lua/packer/handlers/ft.lua

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 12 additions & 10 deletions lua/packer/handlers/keys.lua

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 0 additions & 21 deletions lua/packer/handlers/util.lua

This file was deleted.

5 changes: 0 additions & 5 deletions lua/packer/loader.lua

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 0 additions & 10 deletions lua/packer/plugin.lua

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 11 additions & 11 deletions teal/packer/handlers/cmd.tl
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
local util = require 'packer.handlers.util'
local command_plugins : {string: {Plugin}} = {}

return function(plugins: {string:Plugin}, loader: function({Plugin}))
local commands: {string:{Plugin}} = {}
local new_commands: {string} = {}
for _, plugin in pairs(plugins) do
if plugin.cmd then
for _, cmd in ipairs(plugin.cmd) do
commands[cmd] = commands[cmd] or {}
table.insert(commands[cmd], plugin)
if not command_plugins[cmd] then
command_plugins[cmd] = {}
new_commands[#new_commands + 1] = cmd
end

table.insert(command_plugins[cmd], plugin)
end
end
end

for cmd, cplugins in pairs(commands) do

util.register_destructor(cplugins, function()
vim.api.nvim_del_user_command(cmd)
end)
for _, cmd in ipairs(new_commands) do

vim.api.nvim_create_user_command(cmd,
function(args: vim.api.UserCmdParams)
loader(cplugins)

vim.api.nvim_del_user_command(cmd)
loader(command_plugins[cmd])
local lines = args.line1 == args.line2 and '' or (args.line1 .. ',' .. args.line2)
vim.cmd(string.format(
'%s %s%s%s %s',
Expand Down
25 changes: 11 additions & 14 deletions teal/packer/handlers/event.tl
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
local util = require 'packer.handlers.util'
local event_plugins: {string:{Plugin}} = {}

return function(plugins: {string:Plugin}, loader: function({Plugin}))
local events: {string:{Plugin}} = {}

local new_events: {string} = {}
for _, plugin in pairs(plugins) do
if plugin.event then
for _, event in ipairs(plugin.event) do
events[event] = events[event] or {}
table.insert(events[event], plugin)
if not event_plugins[event] then
event_plugins[event] = {}
new_events[#new_events + 1] = event
end

table.insert(event_plugins[event], plugin)
end
end
end

for event, eplugins in pairs(events) do
for _, event in ipairs(new_events) do
-- Handle 'User Foo' events
local ev, pattern = unpack(vim.split(event, '%s+'))

local id = vim.api.nvim_create_autocmd(ev, {
vim.api.nvim_create_autocmd(ev, {
pattern = pattern,
once = true,
callback = function()
loader(eplugins)
loader(event_plugins[event])
vim.api.nvim_exec_autocmds(event, { modeline = false })
end
})

util.register_destructor(eplugins, function()
pcall(vim.api.nvim_del_autocmd, id)
end)

end
end
Loading

4 comments on commit c89092c

@bangedorrunt
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wbthomason This commit broke my packer config using event. I got the following error:

Error detected while processing BufReadPre Autocommands for "*"..BufReadPr
e Autocommands for "*"..BufReadPre Autocommands for "*"..BufReadPre Autoco
mmands for "*"..BufReadPre Autocommands for "*"..BufReadPre Autocommands f
or "*"..BufReadPre Autocommands for "*"..BufReadPre Autocommands for "*"..
BufReadPre Autocommands for "*"..BufReadPre Autocommands for "*":
E218: autocommand nesting too deep
Error detected while processing BufReadPost Autocommands for "*"..BufReadP
ost Autocommands for "*"..BufReadPost Autocommands for "*"..BufReadPost Au
tocommands for "*"..BufReadPost Autocommands for "*"..BufReadPost Autocomm
ands for "*"..BufReadPost Autocommands for "*"..BufReadPost Autocommands f
or "*"..BufReadPost Autocommands for "*"..BufReadPost Autocommands for "*"
:
E218: autocommand nesting too deep
Error detected while processing BufReadPost Autocommands for "*"..BufReadP
ost Autocommands for "*"..BufReadPost Autocommands for "*"..BufReadPost Au
tocommands for "*"..BufReadPost Autocommands for "*"..BufReadPost Autocomm
ands for "*"..BufReadPost Autocommands for "*"..BufReadPost Autocommands f
or "*"..BufReadPost Autocommands for "*"..BufReadPost Autocommands for "*.
fnl":

Revert to older commit and my config's working as expected

@wbthomason
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinging @lewis6991 also, thanks for the report @bangedorrunt. Can you share your config in a new issue?

@wbthomason
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I think this change is due to the removal of the destructor for event. We trigger the event again during its callback (c89092c#diff-e962cfb497bd4284996e1127113aec6b759f6a3b5290668922a9e3e96d747c3eR26) but before deleting the current event. The once property apparently doesn't delete the autocommand before calling the callback. I replicated this with the following snippet:

vim.api.nvim_create_autocmd('BufReadPost', {
  pattern = '*',
  once = true,
  callback = function()
    print 'triggered'
    vim.api.nvim_exec_autocmds('BufReadPost', { modeline = false })
  end,
})

This might even be an upstream bug?

@bangedorrunt
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wbthomason and @lewis6991, I'm not sure if it's OK to create new issue on experimental commit. My config is written in Fennel lang but I hope it doesn't look strange to you

packer.fnl
(import-macros {: setup!} :core.macros)
(local {: run : map} (require :core.funs))

(fn kvize [xs t]
  (match xs
    [k v] (kvize
            (doto xs (table.remove 1) (table.remove 1))
            (match k
              :init (doto t (tset :config #(: (require v) :setup)))
              :init+ (doto t (tset :config #(: (require (.. :mod. v)) :setup)))
              _ (doto t (tset k v))))
    _ t))
(fn packer-parser []
  "feed a plugin to the plugin manager"
  (var res [])
  (run
    (fn [[plug & args]]
      (match #args
        0 (table.insert res plug)
        _ (->> {1 plug}
               (kvize args)
               (table.insert res))))
    store.plugins)
  res)

(fn load-packer-plugins []
  (let [packer (require :packer)
        opts {:display {:compact true
                        :working_sym ""
                        :error_sym ""
                        :done_sym ""
                        :removed_sym ""
                        :moved_sym ""}
              ;; :opt_default true
              ;; :preview_updates true
              :git {:clone_timeout 180 :depth 1}
              :max_jobs 60}]
    ;; Load packer
    (vim.cmd.packadd :packer.nvim)
    ;; NOTE: packer.startup will be deprecated
    ;; use packer.add, and packer.setup instead
    (packer.startup {1 (packer-parser) :config opts})))

(fn setup []
  (setup! mod)
  (load-packer-plugins)
  (vim.defer_fn #(vim.cmd.do "User PackerDefered") 100))

{: setup}
plugin declaration example
(import-macros {: use : setup!} :core.macros)

(fn setup []
  (use catppuccin/nvim :start true :init+ :ui.catppuccin)
  (use nvim-tree/nvim-web-devicons :start true :init+ :ui.devicons)
  (use echasnovski/mini.tabline :event :UIEnter :init :mini.tabline)
  (use nvim-lualine/lualine.nvim :event :UIEnter :init+ :ui.lualine)
  (use nvim-tree/nvim-tree.lua :event "User PackerDefered" :init+ :ui.nvim-tree)
  (use echasnovski/mini.indentscope :event :BufReadPost :init+ :ui.indentscope))

{: setup}
packer output
 { { "wbthomason/packer.nvim",
    commit = "5cb06da03cccc7ec9f21405df98abf242c9b7b32",
    start = true
  }, { "rktjmp/hotpot.nvim",
    start = true
  }, { "nvim-lua/plenary.nvim",
    start = true
  }, { "catppuccin/nvim",
    config = <function 1>,
    start = true
  }, { "nvim-tree/nvim-web-devicons",
    config = <function 2>,
    start = true
  }, { "echasnovski/mini.tabline",
    config = <function 3>,
    event = "UIEnter"
  }, { "nvim-lualine/lualine.nvim",
    config = <function 4>,
    event = "UIEnter"
  }, { "nvim-tree/nvim-tree.lua",
    config = <function 5>,
    event = "User PackerDefered"
  },
  ...

Please sign in to comment.