Repository: neovim/neovim
File: runtime/lua/vim/pack.lua (Lua)

Code before:
  local plugs = {} --- @type vim.pack.Plug[]
  for i = 1, #specs do
    plugs[i] = new_plug(specs[i], plug_dir)
  end
  plugs = normalize_plugs(plugs)

  -- Pre-process
  lock_read()
  local plugs_to_install = {} --- @type vim.pack.Plug[]
  local needs_lock_write = false
  for _, p in ipairs(plugs) do
    -- Allow to cleanly change `src` of an already installed plugin
    if p.info.installed and plugin_lock.plugins[p.spec.name].src ~= p.spec.src then
      M.del({ p.spec.name })
      p.info.installed = false
    end

    -- Detect `version` change
    local p_lock = plugin_lock.plugins[p.spec.name] or {}
    needs_lock_write = needs_lock_write or p_lock.version ~= p.spec.version
    p_lock.version = p.spec.version
    plugin_lock.plugins[p.spec.name] = p_lock

    -- Register for install
    if not p.info.installed then
      plugs_to_install[#plugs_to_install + 1] = p
      needs_lock_write = true
    end
  end

  -- Install
  if #plugs_to_install > 0 then
    git_ensure_exec()
    install_list(plugs_to_install, opts.confirm)
    for _, p in ipairs(plugs_to_install) do
      if not p.info.installed then
        plugin_lock.plugins[p.spec.name] = nil
      end
    end
  end

  if needs_lock_write then
    lock_write()
  end

  -- Register and load those actually on disk while collecting errors
  -- Delay showing all errors to have "good" plugins added first
  local errors = {} --- @type string[]
  for _, p in ipairs(plugs) do
    if p.info.installed then
      local ok, err = pcall(pack_add, p, opts.load) --[[@as string]]

Review comment (bug):
This seems wrong:

```
Error in /home/aktau/.config/nvim/init.lua:
E5113: Lua chunk: /home/aktau/neovim/share/nvim/runtime/lua/vim/pack.lua:373: spec.src: expected non-empty string, got nil
stack traceback:
        [C]: in function 'error'
        vim/shared.lua: in function 'validate'
        /home/aktau/neovim/share/nvim/runtime/lua/vim/pack.lua:373: in function 'normalize_spec'
        /home/aktau/neovim/share/nvim/runtime/lua/vim/pack.lua:402: in function 'new_plug'
        /home/aktau/neovim/share/nvim/runtime/lua/vim/pack.lua:457: in function 'plug_list_from_names'
        /home/aktau/neovim/share/nvim/runtime/lua/vim/pack.lua:1147: in function 'del'
        /home/aktau/neovim/share/nvim/runtime/lua/vim/pack.lua:827: in function 'add'
```

I don't know how I entered into this branch in the first place, but the invocation itself seems wrong too.

Code after:
--- - Adding plugin second and more times during single session does nothing:
---   only the data from the first adding is registered.
---
--- @param specs (string|vim.pack.Spec)[] List of plugin specifications. String item
--- is treated as `src`.
--- @param opts? vim.pack.keyset.add
function M.add(specs, opts)
  vim.validate('specs', specs, vim.islist, false, 'list')
  opts = vim.tbl_extend('force', { load = vim.v.vim_did_init == 1, confirm = true }, opts or {})
  vim.validate('opts', opts, 'table')

  local plug_dir = get_plug_dir()
  local plugs = {} --- @type vim.pack.Plug[]
  for i = 1, #specs do
    plugs[i] = new_plug(specs[i], plug_dir)
  end
  plugs = normalize_plugs(plugs)

  -- Pre-process
  lock_read()
  local plugs_to_install = {} --- @type vim.pack.Plug[]
  local needs_lock_write = false
  for _, p in ipairs(plugs) do
    -- Allow to cleanly change `src` of an already installed plugin
    if p.info.installed and plugin_lock.plugins[p.spec.name].src ~= p.spec.src then
      M.del({ p.spec.name })
      p.info.installed = false
    end

    -- Detect `version` change
    local p_lock = plugin_lock.plugins[p.spec.name] or {}
    needs_lock_write = needs_lock_write or p_lock.version ~= p.spec.version
    p_lock.version = p.spec.version
    plugin_lock.plugins[p.spec.name] = p_lock

    -- Register for install
    if not p.info.installed then
      plugs_to_install[#plugs_to_install + 1] = p
      needs_lock_write = true
    end
  end

  -- Install
  if #plugs_to_install > 0 then
    git_ensure_exec()
    install_list(plugs_to_install, opts.confirm)
    for _, p in ipairs(plugs_to_install) do
      if not p.info.installed then
        plugin_lock.plugins[p.spec.name] = nil
      end
    end