tzachar / cmp-tabnine

TabNine plugin for hrsh7th/nvim-cmp
MIT License
286 stars 27 forks source link

Tabnine completion being very flaky after special characters (randomly not appearing) #83

Closed luiz00martins closed 1 year ago

luiz00martins commented 1 year ago

Description

My cmp-tabnine, apparently randomly, decides not to display any results after certain punctuations.

Sometimes continuing to type makes it appear, sometimes not. Sometimes running cmp.mapping.complete() (which I have bound to Ctrl+o) makes it appear, sometimes not. Sometimes backspacing one character makes it appear, sometimes not.

Example video

Here's an example video of that I mean:

https://user-images.githubusercontent.com/43142209/208241476-633637c7-2901-4761-99d6-eec02602e0cf.mp4

Note: Ignore the ghost text. It's from GH Copilot, not Tabnine.

It is very weird, and I basically never know when it's going to pop up, and when it isn't.

Now, the failures are deterministic. Each punctuation/special character (<tab>, :, ,, etc) fail in the exact same way, and the mitigations (continuing to type, cmp.mapping.complete, or backspacing) fail/succeed for each one in the exact same pattern each time. Still, it's quite weird that the bug is not consistent across them. None of the mitigations above solves them all.

Config

use {
    'hrsh7th/nvim-cmp',
    requires = {
        'saadparwaiz1/cmp_luasnip',
    },
    config = function()
        local lspkind = require('lspkind')
        local compare = require('cmp.config.compare')
        local luasnip = require('luasnip')

        vim.api.nvim_create_autocmd("CursorHoldI", {
            group = vim.api.nvim_create_augroup("cmp_complete_on_space", {}),
            callback = function()
                local line = vim.api.nvim_get_current_line()
                local cursor = vim.api.nvim_win_get_cursor(0)[2]

                local char_before = string.sub(line, cursor, cursor + 1)

                if char_before == " " or char_before ==  '\t' then
                    require("cmp").complete()
                end
            end,
        })

        local source_mapping = {
            buffer = "[Buffer]",
            nvim_lsp = "[LSP]",
            nvim_lua = "[Lua]",
            luasnip = "[Snip]",
            cmp_tabnine = "[T9]",
            path = "[Path]",
        }

        local cmp = require'cmp'
        cmp.setup({
            snippet = {
                -- REQUIRED - you must specify a snippet engine
                expand = function(args)
                     require('luasnip').lsp_expand(args.body) -- For `luasnip` users.
                end,
            },
            sorting = {
                priority_weight = 2,
                comparators = {
                    require('cmp_tabnine.compare'),
                    compare.offset,
                    compare.exact,
                    compare.score,
                    compare.recently_used,
                    compare.kind,
                    compare.sort_text,
                    compare.length,
                    compare.order,
                },
            },
            mapping = {
                ['<C-b>'] = cmp.mapping(cmp.mapping.scroll_docs(-4), { 'i', 'c' }),
                ['<C-f>'] = cmp.mapping(cmp.mapping.scroll_docs(4), { 'i', 'c' }),
                ['<C-i>'] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }),
                ['<C-o>'] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }),
                --['<C-y>'] = cmp.config.disable, -- Specify `cmp.config.disable` if you want to remove the default `<C-y>` mapping.
                ['<C-e>'] = cmp.mapping({
                    i = cmp.mapping.abort(),
                    c = cmp.mapping.close(),
                }),
                ['<C-n>'] = cmp.mapping(cmp.mapping.select_next_item(), { 'i', 'c' }),
                ['<C-p>'] = cmp.mapping(cmp.mapping.select_prev_item(), { 'i', 'c' }),
                ['<C-y>'] = cmp.mapping(cmp.mapping.confirm({ select = true }), { 'i', 'c' })
            },
            sources = cmp.config.sources({
                { name = 'cmp_tabnine' },
                { name = 'nvim_lsp' },
                { name = 'luasnip' },
                { name = 'path' },
                { name = 'buffer' },
            }),
            formatting = {
                format = function(entry, vim_item)
                    vim_item.kind = lspkind.presets.default[vim_item.kind]
                    --local menu = source_mapping[entry.source.name]
                    local menu = ''
                    if entry.source.name == 'cmp_tabnine' then
                        if entry.completion_item.data ~= nil and entry.completion_item.data.detail ~= nil then
                            menu = entry.completion_item.data.detail .. ' ' .. menu
                        end
                        vim_item.kind = ''
                    end
                    vim_item.menu = menu
                    return vim_item
                end
            },
            experimental = {ghost_text = true},
        })

        -- `/` cmdline setup.
        cmp.setup.cmdline('/', {
            mapping = cmp.mapping.preset.cmdline(),
            sources = {
                { name = 'buffer' }
            }
        })

        -- `:` cmdline setup.
        cmp.setup.cmdline(':', {
            mapping = cmp.mapping.preset.cmdline(),
            sources = cmp.config.sources({
                { name = 'path' }
            }, {
                {
                    name = 'cmdline',
                    option = {
                        ignore_cmds = { 'Man', '!' }
                    }
                }
            })
        })
    end
}

use {
    'tzachar/cmp-tabnine',
    requires = {'hrsh7th/nvim-cmp'},
    run=ternary(vim.g.current_os == 'windows', '.\\install.ps1', './install.sh'),
    config = function()
        local tabnine = require('cmp_tabnine.config')
        tabnine:setup({
            max_lines = 1000;
            max_num_results = 8;
            sort = true;
            run_on_every_keystroke = true;
            snippet_placeholder = '..';
            ignored_file_types = { -- default is not to ignore
                -- uncomment to ignore in lua:
                -- lua = true
            };
            show_prediction_strength = true;
        })
    end
}

Note: I have not yet tried to reduce my config to a MWE, mostly cuz I don't have the time right now. So, this may be some conflict with another source. I'll try to reduce the configs later.

tzachar commented 1 year ago

This is not related to this specific plugin, but to your setup in general. cmp has the following configuration options, which can be set per source, and should help you achieve what you want: https://github.com/hrsh7th/nvim-cmp/blob/8bbaeda725d5db6e4e1be2867a64b43bf547cf06/doc/cmp.txt#L427 https://github.com/hrsh7th/nvim-cmp/blob/8bbaeda725d5db6e4e1be2867a64b43bf547cf06/doc/cmp.txt#L432

I essence, cmp will query completion sources only if the pattern before the cursor matches keyword_pattern and the pattern is at least completion.keyword_length characters.

luiz00martins commented 1 year ago
            sources = cmp.config.sources({
                { name = 'nvim_lsp' },
                { name = 'luasnip' },
                {
                    name = 'cmp_tabnine',
                    keyword_length = 0,
                    keyword_pattern = '*',
                },
                { name = 'path' },
                { name = 'buffer' },
            }),

Now tabnine just doesn't appear. Am I doing something wrong?

tzachar commented 1 year ago

you cant use just ''. its not a valid regular expression. try '.'

luiz00martins commented 1 year ago

Yep, that works way better. It still fails at the beginning of the line though, which is one of the most important cases:

image

(Yes, I've scrolled through all of it, Tabnine isn't in the list)

Any idea on why?

tzachar commented 1 year ago

I can confirm this does not work. I also tested directly with the tabnine process, and no results are returned when the cursor is on the first column of a new line.

It might be a tabnine bug. Can you try to recreate this using vscode and the tabnine plugin for it?

luiz00martins commented 1 year ago

Got some slightly different behaviour on VSCode.

Sometimes it works, sometimes it doesn't: image image

When it doesn't, and calling Alt+] does nothing. But typing a letter and backspacing makes it work again.

tzachar commented 1 year ago

I think this is a bug in tabnine. Maybe try contacting the tabnine team.

luiz00martins commented 1 year ago

Sure, will do.