Packer.nvim: ft = 'filetype' doesn't always work properly

Created on 20 Nov 2020  路  26Comments  路  Source: wbthomason/packer.nvim

Like the title says the ft option doesn't always work e.g. when I do use {tpope/vim-fireplace, ft='clojure'} it seems to work properly, but when I do use {'slashmili/alchemist.vim', ft = 'elixir'} it won't load alchemist. Log file says Sourcing $HOME/path/to/opt/alchemist but it doesn't load. I also use vim-polyglot if it matters and I tried to load alchemist after polyglot, but the result is the same. My plugins.lua for reference:

vim.api.nvim_command('packadd packer.nvim')

return require('packer').startup(function()
    use {'wbthomason/packer.nvim', opt = true}
    use 'srcery-colors/srcery-vim'
    use 'dracula/vim'
    -------------langs-----------
    use 'sheerun/vim-polyglot' -- One for all
    --------------QoL------------
    use 'tpope/vim-surround' -- Surround everything
    use 'scrooloose/nerdcommenter' -- Smart comments
    use 'honza/vim-snippets'
    use 'SirVer/ultisnips'
    use 'jiangmiao/auto-pairs' -- Auto pairs
    use 'vimwiki/vimwiki'
    use {
        'luochen1990/rainbow',
        ft = {'clojure'},
    }
    use {
        'Yggdroot/indentLine',
        ft = {'nim'},
    }
    use 'easymotion/vim-easymotion'
    use 'romgrk/barbar.nvim' -- Best bufferline
    use 'glepnir/galaxyline.nvim'
    use 'farmergreg/vim-lastplace'
    -------------dev tools---------
    use 'majutsushi/tagbar' -- too good to be true
    use {'jaxbot/browserlink.vim', ft = { 'html','css','javascript' }} -- preview
    use {'tpope/vim-fireplace', ft =  'clojure' } -- enables clojure development
    use 'kyazdani42/nvim-tree.lua'
    use {'slashmili/alchemist.vim', ft = 'elixir'}
    ---------------git------------
    use 'tpope/vim-fugitive' -- this should be illegal
    use 'mhinz/vim-signify'
    use 'tpope/vim-rhubarb'
    --------nvim-lsp---------
    use 'neovim/nvim-lspconfig' 
    use 'nvim-lua/diagnostic-nvim'
    use 'nvim-lua/completion-nvim'
    use 'nvim-lua/lsp_extensions.nvim'
    use 'steelsojka/completion-buffers'
    use 'tjdevries/nlua.nvim'
    -------------telescope---------
    use {
        'nvim-lua/telescope.nvim',
        requires = {'nvim-lua/popup.nvim', 'nvim-lua/plenary.nvim'}
    }
    -------------lsputils---------
    use {
        'RishabhRD/nvim-lsputils',
        requires = 'RishabhRD/popfix'
    }
    --------------misc------------
    use {'ron-rs/ron.vim', ft = 'ron'}
    use 'nvim-treesitter/nvim-treesitter'
    use 'kyazdani42/nvim-web-devicons'
    use 'norcalli/nvim-colorizer.lua'
end)

Most helpful comment

We (neovim core) are not bound by unfortunate desicions made by vim. We should change opt/ handling in neovim core to respect the existing after/ pattern properly handled by all plugin/package solutions other than brampackages.

All 26 comments

Interesting. Given that you say it works for Clojure, I assume you're using PackerCompile correctly. Could you please post your compiled file here, and I'll take a look to see if I can figure out what's going on?

This is the compiled file. I also checked the indentLine and ron.vim plugins which I use for nim and ron files respectively. They don't work either.

" Automatically generated packer.nvim plugin loader code

if !has('nvim')
  finish
endif

lua << END
local plugins = {
  ["alchemist.vim"] = {
    loaded = false,
    only_sequence = false,
    only_setup = false,
    path = "/home/kwstas/.local/share/nvim/site/pack/packer/opt/alchemist.vim"
  },
  ["browserlink.vim"] = {
    loaded = false,
    only_sequence = false,
    only_setup = false,
    path = "/home/kwstas/.local/share/nvim/site/pack/packer/opt/browserlink.vim"
  },
  indentLine = {
    loaded = false,
    only_sequence = false,
    only_setup = false,
    path = "/home/kwstas/.local/share/nvim/site/pack/packer/opt/indentLine"
  },
  ["packer.nvim"] = {
    loaded = false,
    only_sequence = false,
    only_setup = false,
    path = "/home/kwstas/.local/share/nvim/site/pack/packer/opt/packer.nvim"
  },
  rainbow = {
    loaded = false,
    only_sequence = false,
    only_setup = false,
    path = "/home/kwstas/.local/share/nvim/site/pack/packer/opt/rainbow"
  },
  ["ron.vim"] = {
    loaded = false,
    only_sequence = false,
    only_setup = false,
    path = "/home/kwstas/.local/share/nvim/site/pack/packer/opt/ron.vim"
  },
  ["vim-fireplace"] = {
    loaded = false,
    only_sequence = false,
    only_setup = false,
    path = "/home/kwstas/.local/share/nvim/site/pack/packer/opt/vim-fireplace"
  }
}

local function handle_bufread(names)
  for _, name in ipairs(names) do
    local path = plugins[name].path
    for _, dir in ipairs({ 'ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin' }) do
      if #vim.fn.finddir(dir, path) > 0 then
        vim.cmd('doautocmd BufRead')
        return
      end
    end
  end
end

_packer_load = nil

local function handle_after(name, before)
  local plugin = plugins[name]
  plugin.load_after[before] = nil
  if next(plugin.load_after) == nil then
    _packer_load({name}, {})
  end
end

_packer_load = function(names, cause)
  local some_unloaded = false
  for _, name in ipairs(names) do
    if not plugins[name].loaded then
      some_unloaded = true
      break
    end
  end

  if not some_unloaded then return end

  local fmt = string.format
  local del_cmds = {}
  local del_maps = {}
  for _, name in ipairs(names) do
    if plugins[name].commands then
      for _, cmd in ipairs(plugins[name].commands) do
        del_cmds[cmd] = true
      end
    end

    if plugins[name].keys then
      for _, key in ipairs(plugins[name].keys) do
        del_maps[key] = true
      end
    end
  end

  for cmd, _ in pairs(del_cmds) do
    vim.cmd('silent! delcommand ' .. cmd)
  end

  for key, _ in pairs(del_maps) do
    vim.cmd(fmt('silent! %sunmap %s', key[1], key[2]))
  end

  for _, name in ipairs(names) do
    if not plugins[name].loaded then
      vim.cmd('packadd ' .. name)
      if plugins[name].config then
        for _i, config_line in ipairs(plugins[name].config) do
          loadstring(config_line)()
        end
      end

      if plugins[name].after then
        for _, after_name in ipairs(plugins[name].after) do
          handle_after(after_name, name)
          vim.cmd('redraw')
        end
      end

      plugins[name].loaded = true
    end
  end

  handle_bufread(names)

  if cause.cmd then
    local lines = cause.l1 == cause.l2 and '' or (cause.l1 .. ',' .. cause.l2)
    vim.cmd(fmt('%s%s%s %s', lines, cause.cmd, cause.bang, cause.args))
  elseif cause.keys then
    local keys = cause.keys
    local extra = ''
    while true do
      local c = vim.fn.getchar(0)
      if c == 0 then break end
      extra = extra .. vim.fn.nr2char(c)
    end

    if cause.prefix then
      local prefix = vim.v.count and vim.v.count or ''
      prefix = prefix .. '"' .. vim.v.register .. cause.prefix
      if vim.fn.mode('full') == 'no' then
        if vim.v.operator == 'c' then
          prefix = '' .. prefix
        end

        prefix = prefix .. vim.v.operator
      end

      vim.fn.feedkeys(prefix, 'n')
    end

    -- NOTE: I'm not sure if the below substitution is correct; it might correspond to the literal
    -- characters \<Plug> rather than the special <Plug> key.
    vim.fn.feedkeys(string.gsub(string.gsub(cause.keys, '^<Plug>', '\\<Plug>') .. extra, '<[cC][rR]>', '\r'))
  elseif cause.event then
    vim.cmd(fmt('doautocmd <nomodeline> %s', cause.event))
  elseif cause.ft then
    vim.cmd(fmt('doautocmd <nomodeline> %s FileType %s', 'filetypeplugin', cause.ft))
    vim.cmd(fmt('doautocmd <nomodeline> %s FileType %s', 'filetypeindent', cause.ft))
  end
end

-- Runtimepath customization

-- Pre-load configuration
-- Setup for: indentLine
loadstring("\27LJ\2\0023\0\0\2\0\4\0\0056\0\0\0009\0\1\0'\1\3\0=\1\2\0K\0\1\0\6|\20indentLine_char\6g\bvim\0")()
-- Setup for: rainbow
loadstring("\27LJ\2\0020\0\0\2\0\3\0\0056\0\0\0009\0\1\0)\1\1\0=\1\2\0K\0\1\0\19rainbow_active\6g\bvim\0")()
-- Post-load configuration
-- Conditional loads
-- Load plugins in order defined by `after`
END

function! s:load(names, cause) abort
call luaeval('_packer_load(_A[1], _A[2])', [a:names, a:cause])
endfunction


" Command lazy-loads

" Keymap lazy-loads

augroup packer_load_aucmds
  au!
  " Filetype lazy-loads
  au FileType javascript ++once call s:load(['browserlink.vim'], { "ft": "javascript" })
  au FileType css ++once call s:load(['browserlink.vim'], { "ft": "css" })
  au FileType clojure ++once call s:load(['vim-fireplace', 'rainbow'], { "ft": "clojure" })
  au FileType elixir ++once call s:load(['alchemist.vim'], { "ft": "elixir" })
  au FileType ron ++once call s:load(['ron.vim'], { "ft": "ron" })
  au FileType nim ++once call s:load(['indentLine'], { "ft": "nim" })
  au FileType html ++once call s:load(['browserlink.vim'], { "ft": "html" })
  " Event lazy-loads
augroup END

Interesting - the FileType commands seem to be uniformly and correctly generated. Could you please tell me what :set filetype reports in an Elixir/Ron/Nim file with this configuration? I suspect that the FileType event is never triggering, but alchemist.vim doesn't look like it defines a ftdetect script, and you said you tried loading polyglot first, so I'm not sure why that would happen...

The filetypes for elixir and nim are correct. The filetype for ron is empty which I guess makes sense since it needs the plugin, but when I used vim-plug and did Plug 'ron-rs/ron.vim', {'for': 'ron'} it worked fine. I'm not sure I loaded polyglot first correctly though. I tried using the after option like after = 'sheerun/vim-polyglot' and after = 'vim-polyglot', but none of them worked.

I have tested this with a clean instance of Neovim (no plugins or config) and... this looks like it could be a quirk of :packadd?

This works:

  • Clone slashmili/alchemist.vim in start
  • Open Neovim
  • :scriptnames reveals that after/plugin/alchemist.vim has been sourced

This doesn't:

  • Clone slashmili/alchemist.vim in opt
  • Open Neovim
  • :packadd alchemist.vim
  • :scriptnames reveals that after/plugin/alchemist.vim has not been sourced

It only seems to affect files in after/plugin. I have no idea if this is the intended behavior or not.

Yeah when I tried without the ft option everything worked fine. Maybe I should fine another workaround.

@bfredl is there any chance the recent changes to native packages could be affecting this?

@nanotee thanks for testing that!

If this is "working as intended" for packadd, then perhaps I should add a manual check + sourcing for after/* files...

dunno, someone else had a similar problem and then it turned out something else was a problem. after/ behaviour is not changed by my recent changes at least :D

Hmm it is a little bit suspicious that packer.nvim is manually doing after/ stuff at all. the core plugin code (already the code inherited from vim) is _supposed_ to handle all that (if it does not I will fix it)

So, unless I'm forgetting something I implemented, we currently aren't doing anything manually with after/. It's just that we might have to add something to manually source files in if this problem reproduces and isn't an issue with packadd.

I was just reading what the "Automatically generated packer.nvim plugin loader code" was doing but maybe I misunderstood it.

Ah - if you're referring to the handle_after function, that's for handling packer's sequence loading keyword, which is (confusingly) also after.

Looks like this is the intended behavior: https://github.com/vim/vim/issues/1994

Unfortunate (but thanks @nanotee for the find!)

packer could add manual handling of after/plugin/, but, as @bfredl mentions, that seems fishy/like maybe a bad idea. Still, given that I disagree with the reasoning in https://github.com/vim/vim/issues/1994 (it may be an anti-pattern, but plugins should still be sourced the same whether or not they're in start or opt), this might be the best way to go.

We (neovim core) are not bound by unfortunate desicions made by vim. We should change opt/ handling in neovim core to respect the existing after/ pattern properly handled by all plugin/package solutions other than brampackages.

Hmm, opt/xx/after/plugin/xx.vim actually work for me when packadd! xx. Is there a complete minimal example of a config where it does not work?

I think the config @nanotee describes here is probably the closest to a complete minimal config demonstrating the behavior.

@bfredl Interestingly, packadd xx on its own in init.vim seems to work, but the following doesn't source files in after/plugin:

autocmd VimEnter * packadd xx

I just ran into an issue with whonore/Coqtail#162 that might also fall under the scope of this issue. Precisely, it is a syntax file which does not get sourced when restricted to only load on its own filetype (using :scriptnames confirms this):

use {'whonore/Coqtail', ft='coq'}
nvim foo.v   # no syntax highlighting
nvim foo.coq # no syntax highlighting

But, if I run :setf coq one more time, the highlighting happens.

To compare, doing:

Plug 'whonore/Coqtail', {'for': 'coq'}

works.


To workaround this issue, I created the following file:

" ~/.config/nvim/ftplugin/coq/filetype.vim
setf coq

And it works.

Do you also encounter this error when packadding the plugin manually? i.e. does this seem to be an issue with how packer implements ft vs. how vim-plug implements for, or with how Neovim/Vim implement native packages?

Yeah, packadding manually makes it work. This is what I did:

  1. Comment out the use for Coqtail:
    lua -- use {'whonore/Coqtail', ft='coq'}
  2. :PackerCompile
  3. Modify ~/.config/nvim/ftplugin/coq/filetype.vim:
    packadd Coqtail

That makes it work.


Edit: to clarify, it seems this is not an issue with the Neo/vim package implementation. Rather, a load order issue.

Well, that's unfortunate.

It looks like vim-plug does some explicit sourcing to handle this case (https://github.com/junegunn/vim-plug/blob/master/plug.vim#L387); perhaps packer needs something similar...

Should I make a separate issue for that?

I added a mechanism to fix a related issue in #215; I should be able to extend it to also handle this case.

@Iron-E: I think 993eaad fixes this (at least, I can no longer reproduce your Coqtail issue). Please reopen if you're still seeing problems, and thanks for your patience on this!

Awesome! Glad to see this fixed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

GustavoPrietoP picture GustavoPrietoP  路  7Comments

clason picture clason  路  5Comments

clason picture clason  路  4Comments

nanotee picture nanotee  路  7Comments

clason picture clason  路  5Comments