hrsh7th / nvim-cmp

A completion plugin for neovim coded in Lua.
MIT License
8.09k stars 400 forks source link

LuaSnip integration causing a bunch of problems #180

Closed ExpandingMan closed 3 years ago

ExpandingMan commented 3 years ago

I apologize for the vagueness of the title but, I'm having a rather hard time tracking down what's going on. I'm trying to integrate LuaSnip with cmp_luasnip (I don't think these problems are the fault of that plugin but I'm not entirely sure...)

First, I can't seem to get any LuaSnip functionality other than inserting snippets to work. Snippets match fine, they insert fine, but keybindings for jumping between snippet fields don't work at all. Again, not really sure whether this is an nvim-cmp issue, a LuaSnip issue, or some combination.

Second, sometimes, for no apparent reason, <tab> completion just stops working (inserts a tab instead). All other bindings continue to work fine, but not tab. This problem is the same regardless of whether I use the built-in cmp.mapping.select_next_item() or the supertab-like mapping in the README. I have this problem ONLY when enabling the luasnip completion source but it doesn't seem to have anything to do with whether I've inserted a snippet or there are snippets available. Unfortunately I've failed to reproduce the exact circumstances of this issue, and it seems to happen randomly.

For context, my config is here with my cmp config here and my luasnip config here (some functionality has been temporarily removed so I have a working cmp).

hrsh7th commented 3 years ago

It looks like tabfunc is not used. https://gitlab.com/ExpandingMan/neovimconfig/-/blob/master/lua/etc/completion.lua#L16

ExpandingMan commented 3 years ago

Not right at the moment, sorry I should have been more explicit: these problems are the same regardless of whether I use that tabfunc or the built-in. Doesn't seem to be any difference. The config at the moment happens not to be using tabfunc but I have tested it.

And, just to be extra explicit: no I don't have LuaSnip bindings in there right now, but when I added them they did not work, and I don't mean the binding to tab, I mean all bindings for LuaSnip.

ExpandingMan commented 3 years ago

Ok, looks like whatever makes tab stop working is not only because of LuaSnip. I'm now seeing the problem even without it, so it must be some kind of cmp bug, probably from interaction with another plugin. I'm going to try tree-searching my config when I get a chance, but it's going to be really hard to track down, because it isn't initially a problem (though once it starts happening it keeps happening until I exit).

Another fact that may be relevant: <c-n> never stops working, only <tab> (which reverts to just inserting a tab).

Any suggestions on how to debug this would be appreciated, maybe I can try sticking print statements into the tab keybinding...

rafamadriz commented 3 years ago

I have the following config and tab works perfectly fine:

local fn = vim.fn

local function t(str)
    return vim.api.nvim_replace_termcodes(str, true, true, true)
end

local check_back_space = function()
    local col = vim.fn.col "." - 1
    return col == 0 or vim.fn.getline("."):sub(col, col):match "%s" ~= nil
end

local function tab(fallback)
    local luasnip = require "luasnip"
    if fn.pumvisible() == 1 then
        fn.feedkeys(t "<C-n>", "n")
    elseif luasnip.expand_or_jumpable() then
        fn.feedkeys(t "<Plug>luasnip-expand-or-jump", "")
    elseif check_back_space() then
        fn.feedkeys(t "<tab>", "n")
    else
        fallback()
    end
end

local function shift_tab(fallback)
    local luasnip = require "luasnip"
    if fn.pumvisible() == 1 then
        fn.feedkeys(t "<C-p>", "n")
    elseif luasnip.jumpable(-1) then
        fn.feedkeys(t "<Plug>luasnip-jump-prev", "")
    else
        fallback()
    end
end

local cmp = require "cmp"

    cmp.setup {
        snippet = {
            expand = function(args)
                require("luasnip").lsp_expand(args.body)
            end,
        },
        mapping = {
            ["<Tab>"] = cmp.mapping(tab, { "i", "s" }),
            ["<S-Tab>"] = cmp.mapping(shift_tab, { "i", "s" }),
            ["<C-d>"] = cmp.mapping.scroll_docs(-4),
            ["<C-f>"] = cmp.mapping.scroll_docs(4),
            ["<C-Space>"] = cmp.mapping.complete(),
            ["<C-e>"] = cmp.mapping.close(),
            ["<CR>"] = cmp.mapping.confirm {
                behavior = cmp.ConfirmBehavior.Insert,
                select = true,
            },
        },
    }

with that, I can jump between the snippets stops and tab completion never stops working for me. @ExpandingMan can you test the config above ?

kdheepak commented 3 years ago

I'm trying this setup, and luasnip.expand_or_jumpable() is always false after the first expand. Maybe I'm missing some configuration option for luasnip? Can you share your luasnip config too?

This is currently what I'm using:

        use {
          "L3MON4D3/LuaSnip",
          config = function()
            require("luasnip").config.setup({ history = false })
          end,
        },

edit:

My bad, I had an autocmd to disable snippets that I forgot to remove. Everything is working for me, ignore the above comment.

ExpandingMan commented 3 years ago

I've been experimenting more and maybe it's less likely to break without the check_backspace condition? (Not sure I understand why that's needed anyway.)

It's really infuriating because nothing has been consistent. I'll load it up and it seems perfectly fine for a while, maybe I think I've fixed it, and then all of the sudden it just stops working. No idea what changes when it breaks. Can't even get it to happen consistently yet.

rafamadriz commented 3 years ago

You need to set history to true, otherwise lusnip doesn't remember positions and you can't jump back, only forward.

        config = function()
            require("luasnip").config.set_config {
                history = true,
            }
            require("luasnip.loaders.from_vscode").load {}
        end,
ExpandingMan commented 3 years ago

@rafamadriz , I've always had history=true. Indeed, the example you showed was one of the first things I had tried, and it was breaking (and jumping was not working). It's even possible that it would have broken for you, like I said, it's maddeningly intermittent. It of course seems likely that whatever is happening is caused by something somewhere else in my config, but I just have no clue what that could be.

Btw, I've just now made sure I updated all of my neovim instances to latest nightly (previously I had been using a random assortment of 0.6 nightlies) we'll see if that helps. Could have been a neovim issue, who knows.

kdheepak commented 3 years ago

I think @rafamadriz was replying to me about the history. Sorry for hijacking the thread. Everything is working for me, even shift tab, with history = false. The history is for when you exit a snippet and want to jump back in to continue.

rafamadriz commented 3 years ago

I think @rafamadriz was replying to me about the history. Sorry for hijacking the thread. Everything is working for me, even shift tab, with history = false. The history is for when you exit a snippet and want to jump back in to continue.

oh sorry I didn't realize there was a new person in the thread lol. Yes, you're right, history is for when you exit a snippet.

rafamadriz commented 3 years ago

@rafamadriz , I've always had history=true. Indeed, the example you showed was one of the first things I had tried, and it was breaking (and jumping was not working). It's even possible that it would have broken for you, like I said, it's maddeningly intermittent. It of course seems likely that whatever is happening is caused by something somewhere else in my config, but I just have no clue what that could be.

Btw, I've just now made sure I updated all of my neovim instances to latest nightly (previously I had been using a random assortment of 0.6 nightlies) we'll see if that helps. Could have been a neovim issue, who knows.

Interesting, I hope you can fix it by updating your neovim or maybe just using the stable release 0.5 which is what I use and have no problems.

ExpandingMan commented 3 years ago

Ok, it definitely still happens on latest neovim.

I think I'm seeing a weird pattern though... it seems to have something to do with switching buffers... a lot of times I will have the tab problem on a new buffer, but it still works ok on a previously existing buffer... trying to use this to come up with an MWE...

kdheepak commented 3 years ago

Try running :verbose imap <Tab> when you notice you have the problem. We should make sure it is not being remapped to something else.

ExpandingMan commented 3 years ago

Ok, I think I may have some idea of what's causing it... I think it has something to do with julia-vim latex-to-unicode. Fortunately, that package lets you keep using the autocomplete while disabling tab complete, plus I am using @kdheepak 's latex plugin, so that mapping wasn't really doing anything for me.

Disabling this did NOT solve my problem with LuaSnip. It may have solved my problem with tab stopping working, but it's still too early to say, will report back...

Pretty sure I don't have anything else overloading tab now.

kdheepak commented 3 years ago

For what it is worth, I have the following in my packer config:

    use({
      "JuliaEditorSupport/julia-vim",
      ft = { "julia" },
      fn = { "LaTeXToUnicode#Refresh" },
      config = function()
        vim.g.latex_to_unicode_tab = "off"
        vim.g.latex_to_unicode_auto = 0
      end,
    })
ExpandingMan commented 3 years ago

Ok... I think finally some progress (though this has been so intermittent I'm always afraid to say anything with confidence)...

I think the most egregious tab problem was indeed an issue with julia-vim. Again, fortunately I have redundant functionality here so it cost me nothing to turn that off.

I'm still having a few weird problems with LuaSnip jumping. It works in the first buffer I open, but not subsequent buffers. It's really weird. Also my <cr> as cmp.mapping.confirm mysteriously stops working (but for LuaSnip only so its not so bad) perhaps under the same circumstances that were previously breaking tab. Now that things are a little less bewildering, I'm going to overhaul my bindings to make better use of LuaSnip and see if I can get something consistent. I strongly suspect that whatever issues remain are the fault of LuaSnip (or maybe the cmp plugin for it) not cmp itself, so I doubt there's anything to be done here.

Will update later after I get a chance to mess around with it, and if the situation is unchanged, I'll close the issue.

Thanks for the help all!

ExpandingMan commented 3 years ago

Alright, I think I've now fully solved this.

So the tab issue definitely seems to have been julia-vim. Again, it was redundant and I probably should have removed that in the first place.

Otherwise, it seems that LuaSnip and nvim-cmp both really want to use a lot of the same bindings (in particular <tab>, <c-n>, <c-p>) and these are very likely to cause problems for each other unless you are very careful with your bindings. Creating the tabfunc which would bind to <c-n> which was being used by both plugins by default made things very confusing.

For me, trying to overload the same few keybindings with so much functionality in the same mode seems like a bad approach anyway, so I'm pretty happy to just change the key bindings for LuaSnip to something completely different, in which case these two packages work together rather nicely. So that basically settles it for me.

Unless you want to recommend people do the same, I suggest you ultimately stick functions like the "supertab" above into the package somewhere so it's a little easier to get working defaults, as I suspect that others will run into at least some of these issues.

Thanks all!

ExpandingMan commented 3 years ago

For what it's worth, I'm kind of glad I struggled with this for a bit, because I'm much more satisfied with the result than I likely would have been had I not given it much more thought. Instead of trying to load everything into <tab> and <c-n> etc., I now have a dedicated leader (<c-s>) for jumping through and choosing snippets that works the same way in insert, normal and select mode. For me, this is much easier to use than how I had snippets before (plus LuaSnip is way better at remembering positions than UltiSnips was). So I'm pretty happy now!