hrsh7th / nvim-cmp

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

Error executing lua .../.vim/plugged/nvim-cmp/lua/cmp/config/default.lua:23: snippet engine is not configured. #102

Closed acicco closed 3 years ago

acicco commented 3 years ago

Hi there,

I'm transitioning from nvim-compe, I managed to get it almost running with the same settings as with compe, however when I try to complete a lsp snippet it throws with the title error.

Can I get some help please? it gets replaced with a 0 when I hit enter image

image

hrsh7th commented 3 years ago

@acicco Do you dislike snippet engine? I think it will be solved if you install snippet engine. What should I do with the get ~ item if I don't set up the snippet engine?

JoseConseco commented 3 years ago

I had simmilar error - it was caused by bad mapping config (it is better to create new config from cmp readme, rather than trying to convert old compe mappings config imo - or else u end up with above bug). Here is config that worked witout error (I use tab, to cycle through entries, or just to snippet tabstops; ctrl+space accepts selected item, or expands snippet ) :+1:

mapping = {
        ['<C-p>'] = cmp.mapping.select_prev_item(),
        ['<C-n>'] = cmp.mapping.select_next_item(),
        ['<S-Tab>'] = function(fallback)
                if vim.fn['vsnip#jumpable']() == 1 then
                    vim.fn.feedkeys(t('<plug>(vsnip-jump-prev)'), '')
                elseif vim.fn.pumvisible() == 1 then
                    vim.fn.feedkeys(t('<C-p>'), '')
                else
                    fallback()
                end
        end,
        ['<Tab>'] = function(fallback)
                if vim.fn['vsnip#jumpable']() == 1 then
                    vim.fn.feedkeys(t('<plug>(vsnip-jump-next)'), '')
                elseif vim.fn.pumvisible() == 1 then
                    vim.fn.feedkeys(t('<C-n>'), '')
                else
                    fallback()
                end
        end,
        ['<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,
        }),
        ['<C-Space>'] = function(fallback)
            if vim.fn['vsnip#available']() == 1 then
                vim.fn.feedkeys(t('<Plug>(vsnip-expand-or-jump)'), '')
            elseif vim.fn.pumvisible() == 1 then
                vim.fn.feedkeys(t('<CR>'), '')
            else
                fallback()
            end
        end,
    }
Iron-E commented 3 years ago

I am getting the same thing. I think it is related to attempting to use the builtin snippet support, rather than installing a snippet engine. With nvim-compe the following LSP configuration allowed for snippet support, without installing vsnip, LuaSnip, etc.:

local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true
capabilities.textDocument.completion.completionItem.resolveSupport =
{
    properties =
    {
        'documentation',
        'detail',
        'additionalTextEdits',
    }
}

lspconfig['<server>'].setup {capabilities = capabilities}

However, trying this gives the following in cmp:

E5108: Error executing lua ...te/pack/packer/start/nvim-cmp/lua/cmp/config/default.lua:23: snippet engine is not configured.

Edit: seems it's not related, others are using snippet engines and still have issue

acicco commented 3 years ago

@acicco Do you dislike snippet engine? I think it will be solved if you install snippet engine. What should I do with the get ~ item if I don't set up the snippet engine?

@hrsh7th

I do have a snippet engine installed, I have vsnips, I followed the instructions and added it to the sources, is there anything else I should do?

bangedorrunt commented 3 years ago

Have you tried this? https://github.com/hrsh7th/cmp-nvim-lsp

Iron-E commented 3 years ago

I'm personally using that, don't know about OP

bragmore commented 3 years ago

I'm having the same issue, also using cmp-nvim-lsp and luasnip

avatsavirs commented 3 years ago

I'm getting the same error. I tried installing vim-vsnip and cmp-vsnip as dependencies(using packer.nvim) for nvim-cmp and added cmp-vsnip in my sources but it didn't work for me. Also is there a way to opt out of using the snippet engine completely? I don't want to cmp to complete the signatures for the selected function as I'm often passing a function as an argument. I liked how compe just selected the function name. It would be really nice if using signatures was an optional feature. Let me know if I can do anything to help in solving this issue. Thanks.

PS: This is my config for reference: /lua/plugins/init.lua

vim.cmd([[ packadd packer.nvim ]]);

return require('packer').startup({
  function(use)
    use({
      "hrsh7th/nvim-cmp",
      config = [[ require('plugins.nvim-cmp') ]],
      requires = {
        "hrsh7th/cmp-nvim-lsp",
        "hrsh7th/cmp-buffer",
        "hrsh7th/cmp-path",
        "hrsh7th/vim-vsnip",
        "hrsh7th/cmp-vsnip",
      }
    });
  end
});

/lua/plugins/nvim-cmp.lua

local cmp = require('cmp');
local types = require('cmp.types');

local check_back_space = function()
  local col = vim.fn.col('.') - 1;
  if col == 0 or vim.fn.getline('.'):sub(col, col):match '%s' then
    return true
  else
    return false
  end
end

local custom_select_next = function()
  if vim.fn.pumvisible() == 1 then
    vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<C-n>', true, true, true), 'n');
  elseif check_back_space() then
    vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<Tab>', true, true, true), 'n');
  else
    local cmp_complete = cmp.mapping.complete();
    cmp_complete();
  end
end

cmp.setup({
  preselect = types.cmp.PreselectMode.Item,
  mapping = {
    ['<S-Tab>'] = cmp.mapping.select_prev_item(),
    ['<Tab>'] = custom_select_next,
    ['<C-Space>'] = cmp.mapping.complete(),
    ['<C-e>'] = cmp.mapping.close(),
    ['<CR>'] = cmp.mapping.confirm({
      behavior = cmp.ConfirmBehavior.Insert,
      select = true,
    })
  },
  sources = {
    { name = 'nvim_lsp' },
    { name = 'buffer' },
    { name = 'path' },
    { name = 'vsnip' }
  },
});
hrsh7th commented 3 years ago

I understoo dIt's documentation bug. Please wait.

bangedorrunt commented 3 years ago

hmm, I haven't got this issue, here is my config, sorry, it's written in fennel but hope it give you some clues

;; nvim-cmp.fnl
(def- cmp-srcs
  [{:name :nvim_lsp}
   {:name :conjure}
   {:name :luasnip}
   {:name :buffer}
   {:name :path}
   {:name :nvim_lua}
   {:name :calc}
   {:name :emoji}])

(defn- check-back-space []
  (let [col (- (vim.fn.col ".") 1)]
    (if (or (= col 0) (: (: (vim.fn.getline ".") :sub col col) :match "%s"))
        true false)))

(cmp.setup
  {:formatting
   {:format (fn [entry item]
              (set item.kind
                   (.. (or (get cmp-kinds item.kind) "")
                       " " item.kind))
              (set item.menu (or (get cmp-src-menu-items entry.source.name) ""))
              item)}
   :mapping
   {:<C-p> (cmp.mapping.select_prev_item)
    :<C-n> (cmp.mapping.select_next_item)
    :<Up> (cmp.mapping.scroll_docs -4)
    :<Down> (cmp.mapping.scroll_docs 4)
    :<C-s> (cmp.mapping.complete)
    :<C-e> (cmp.mapping.close)
    ;; :<CR> (cmp.mapping.confirm
    ;;         {:behavior cmp.ConfirmBehavior.Insert
    ;;          :select true})
    :<Tab> (cmp.mapping (fn [fallback]
              (if (= (vim.fn.pumvisible) 1) (vim.fn.feedkeys (t :<C-n>) "n")
                (and luasnip (luasnip.expand_or_jumpable)) (vim.fn.feedkeys (t :<Plug>luasnip-expand-or-jump) "")
                (check-back-space) (vim.fn.feedkeys (t :<Tab>) "n")
                (fallback))) ["i" "s"])
    :<S-Tab> (cmp.mapping (fn [fallback]
                (if (= (vim.fn.pumvisible) 1)
                  (vim.fn.feedkeys (t :<C-p>) "n")
                  (and luasnip (luasnip.jumpable (- 1))) 
                   (vim.fn.feedkeys (t :<Plug>luasnip-jump-prev) "")
                   (vim.fn.feedkeys (t :<S-Tab>) "n")
                  (fallback))) ["i" "s"])}
   :snippet
   {:expand (fn [args]
              (luasnip.lsp_expand args.body))}
   :sources cmp-srcs})
;; Load friendly-snippets
(snippet.lazy_load)

and this is lspconfig setup

;; lsp.fnl
(local cmp/lsp (require :cmp_nvim_lsp))

(def- capabilities
  (let [c (vim.lsp.protocol.make_client_capabilities)]
    ;; Delegate snippet support to any completion engine such as `nvim-cmp`
    (set c.textDocument.completion.completionItem.snippetSupport true)
    (set c.textDocument.completion.completionItem.resolveSupport {:properties [:documentation
                                                                               :detail
                                                                               :additionalTextEdits]})
    (set c.textDocument.completion.completionItem.preselectSupport true)
    (set c.textDocument.completion.completionItem.insertReplaceSupport true)
    (set c.textDocument.completion.completionItem.deprecatedSupport true)
    (set c.textDocument.completion.completionItem.commitCharactersSupport true)
    (set c.textDocument.completion.completionItem.tagSupport {:valueSet [1]})
    ;; Code action
    ;; (set c.textDocument.codeAction
    ;;      {:dynamicRegistration true
    ;;       :codeActionLiteralSupport {:codeActionKind {:valueSet ((fn []
    ;;                                                                (def- res
    ;;                                                                  (vim.tbl_values vim.lsp.protocol.CodeActionKind))
    ;;                                                                (table.sort res)
    ;;                                                                res))}}})
    (cmp/lsp.update_capabilities c)))

;; .....
;; .....
(each [server config (pairs servers)]
  (let [lsp/server (. lspconfig server)]
        (-> {:on_attach enhanced-attach
             ;; This will merge our defined capabilities to each lspserver in the list
             : capabilities  
             :flags {:debounce_text_changes 150}}
            (merge config)
            (lsp/server.setup))))

Pls note that I trimmed down some unwanted codes.

hrsh7th commented 3 years ago

@babygau Thank you. Because you've set nvim-cmp up correctly.

@acicco @avatsavirs @Iron-E I've updated the README.md See https://github.com/hrsh7th/nvim-cmp#basic-configuration

We must set snippet.expand up.

And I've added minimal vimrc (it works with nvim-lspconfig). https://github.com/hrsh7th/nvim-cmp/blob/main/utils/vimrc.vim

Iron-E commented 3 years ago

Is there a snippet.expand function that doesn't require a dedicated snippet plugin but also supports the ? compe had LSP snippet expansion builtin and I'm trying to replicate that.

I'll play around with it in the meantime but if there is an existing solution I won't reinvent the wheel.

Thank you!


Edit: I found a solution that works pretty well, and doesn't need a snippet engine installed.

snippet =
{
    expand = function(args)
        local line_num, col = unpack(vim.api.nvim_win_get_cursor(0))
        local line_text = vim.api.nvim_buf_get_lines(0, line_num - 1, line_num, true)[1]
        local indent = string.match(line_text, '^%s*')
        local replace = vim.split(args.body, '\n', true)

        local surround = string.match(line_text, '%S.*') or ''
        replace[1] = surround:sub(0, col - 2)..replace[1]..surround:sub(col - 1)
        if indent ~= '' then
            for i, line in ipairs(replace) do
                replace[i] = indent..line
            end
        end

        vim.api.nvim_buf_set_lines(0, line_num - 1, line_num, true, replace)
    end,
}

Edit 2: Fixed bug relating to cursor position


Edit 3: Fixed bug relating to words after snippet expansion, now with 0% vim.fn. Thanks @ibhagwan for letting me know about the bug.

hrsh7th commented 3 years ago

I think your solution has a cursor position problem... but good to hear.

acicco commented 3 years ago

Thanks a lot @hrsh7th , with your basic configuration I get what I had on compe, I prefer how vsnip completes my snippets rather than luasnips

bragmore commented 3 years ago

@hrsh7th I'm still getting the same error even after reading the updated readme. Am I doing something wrong?

This is my cmp.lua config file:

local present, cmp = pcall(require, "cmp")
if not present then
    return
end

cmp.setup({
    confirmation = { default_behaviour = cmp.ConfirmBehavior.Replace },
    sources = {
        { name = "buffer" },
        { name = "nvim_lsp" },
        { name = "nvim_lua" },
        { name = "path" },
        { name = "vsnip" }
    },
    mapping = {
        ["<cr>"] = cmp.mapping.confirm(),
        ["<s-tab>"] = cmp.mapping.select_prev_item(),
        ["<tab>"] = cmp.mapping.select_next_item(),
    },
    formatting = {
        format = function(entry, vim_item)
            vim_item.menu = ({
                buffer = "[Buffer]",
                nvim_lsp = "[LSP]",
                vsnip = "[vsnip]",
                nvim_lua = "[Lua]",
                latex_symbols = "[Latex]",
            })[entry.source.name]
            vim_item.kind = ({
                Text          = ' Text',
                Method        = ' Method',
                Function      = ' Function',
                Constructor   = ' Constructor',
                Field         = ' Field',
                Variable      = ' Variable',
                Class         = ' Class',
                Interface     = 'ﰮ Interface',
                Module        = ' Module',
                Property      = ' Property',
                Unit          = ' Unit',
                Value         = ' Value',
                Enum          = ' Enum',
                Keyword       = ' Keyword',
                Snippet       = '﬌ Snippet',
                Color         = ' Color',
                File          = ' File',
                Reference     = ' Reference',
                Folder        = ' Folder',
                EnumMember    = ' EnumMember',
                Constant      = ' Constant',
                Struct        = ' Struct',
                Event         = ' Event',
                Operator      = 'ﬦ Operator',
                TypeParameter = ' TypeParameter',
            })[vim_item.kind]
            return vim_item
        end,
        snippet = {
            expand = function(args)
                vim.fn["vsnip#anonymous"](args.body)
            end
        },
    },
})

This is from my plugins.lua file:

    -- Completion engine
    use { 
        'hrsh7th/nvim-cmp',
        requires = {
            {'hrsh7th/cmp-buffer'},
            {'hrsh7th/cmp-nvim-lsp'},
            {'hrsh7th/vim-vsnip'},
            {'hrsh7th/cmp-buffer'}
        },
        -- Cmp config
        config = function() require("config.cmp") end
    }

    -- Snippets collection for all kinds of different programming languages
    use {
        "rafamadriz/friendly-snippets"
    }

cmp seems to work but not snippets, I simply get the error "snippet engine is not configured."

hrsh7th commented 3 years ago

@bragjo I don't found the cause in your part of config. Could you provide your full config?

acicco commented 3 years ago

@bragjo Could it be that you're missing {'hrsh7th/cmp-vsnip'} in your requires map?

bragmore commented 3 years ago

@bragjo I don't found the cause in your part of config. Could you provide your full config?

Here is my complete plugins.lua:

local fn = vim.fn
local install_path = fn.stdpath('data')..'/site/pack/packer/start/packer.nvim'
if fn.empty(fn.glob(install_path)) > 0 then
    fn.system({'git', 'clone', 'https://github.com/wbthomason/packer.nvim', install_path})
    vim.cmd 'packadd packer.nvim'
end

return require('packer').startup(function()

    -- Packer can manage itself
    use 'wbthomason/packer.nvim'

    -- Lsp config and cmp-nvim-lsp
    use {
        'neovim/nvim-lspconfig',
        config = function() require("config.lspconfig") end
    }

    -- Lspinstall for easier installation of LSPs via :LspInstall
    use {
        'kabouzeid/nvim-lspinstall',

        -- LspInstall config
        config = function() require("config.lspinstall") end
    }

        -- Completion engine
    use { 
        'hrsh7th/nvim-cmp',
        requires = {
            'hrsh7th/cmp-buffer',
            'hrsh7th/cmp-nvim-lsp',
            'hrsh7th/vim-vsnip',
            'hrsh7th/cmp-vsnip',
            'hrsh7th/cmp-buffer',
        },
        -- Cmp config
        config = function() require("config.cmp") end
    }

     -- Snippets collection for all kinds of different programming languages
    use {
        "rafamadriz/friendly-snippets"
    }

    -- Galaxyline base
    use {
        'glepnir/galaxyline.nvim',
        branch = 'main',

        -- Galaxyline config
        config = function() require("config.galaxyline") end,

        -- Some optional icons
        requires = {'kyazdani42/nvim-web-devicons', opt = true}
    }

    -- Show colors instead of just hexcode in e.g. css via colorizer
    use {
        'norcalli/nvim-colorizer.lua',

        -- Colorizer config
        config = function() require("config.colorizer") end
    }

    -- Telescope fuzzy finder
    use {
        'nvim-telescope/telescope.nvim',
        requires = {{'nvim-lua/popup.nvim'}, {'nvim-lua/plenary.nvim'}},

        -- Telescope config
        config = function() require("config.telescope") end
    }

    -- Bufferline
    use {
        'akinsho/bufferline.nvim', 
        requires = 'kyazdani42/nvim-web-devicons'
    }

    -- Colorscheme tokyonight
    use {
        'ghifarit53/tokyonight-vim'
    }

    -- Better syntax highlightning via treesitter
    use {
        'nvim-treesitter/nvim-treesitter',
        run = ':TSUpdate',

        -- Treesitter config
        config = function() require("config.treesitter") end
    }

    -- Easy commenting/uncommenting using nvim-comment

    use {
        use "terrortylor/nvim-comment",
        require('nvim_comment').setup()

    }

    -- Live preview when working with frontend stuff
    use {
        'turbio/bracey.vim',
        run = "'do': 'npm install --prefix server'"
    }

end)

and this is the full config / cmp.lua file:

local present, cmp = pcall(require, "cmp")
if not present then
    return
end

cmp.setup({
    confirmation = { default_behaviour = cmp.ConfirmBehavior.Replace },
    sources = {
        { name = "buffer" },
        { name = "nvim_lsp" },
        { name = "nvim_lua" },
        { name = "path" },
        { name = "vsnip" }
    },
    mapping = {
        ["<cr>"] = cmp.mapping.confirm(),
        ["<s-tab>"] = cmp.mapping.select_prev_item(),
        ["<tab>"] = cmp.mapping.select_next_item(),
    },
    formatting = {
        format = function(entry, vim_item)
            vim_item.menu = ({
                buffer = "[Buffer]",
                nvim_lsp = "[LSP]",
                vsnip = "[vsnip]",
                nvim_lua = "[Lua]",
                latex_symbols = "[Latex]",
            })[entry.source.name]
            vim_item.kind = ({
                Text          = ' Text',
                Method        = ' Method',
                Function      = ' Function',
                Constructor   = ' Constructor',
                Field         = ' Field',
                Variable      = ' Variable',
                Class         = ' Class',
                Interface     = 'ﰮ Interface',
                Module        = ' Module',
                Property      = ' Property',
                Unit          = ' Unit',
                Value         = ' Value',
                Enum          = ' Enum',
                Keyword       = ' Keyword',
                Snippet       = '﬌ Snippet',
                Color         = ' Color',
                File          = ' File',
                Reference     = ' Reference',
                Folder        = ' Folder',
                EnumMember    = ' EnumMember',
                Constant      = ' Constant',
                Struct        = ' Struct',
                Event         = ' Event',
                Operator      = 'ﬦ Operator',
                TypeParameter = ' TypeParameter',
            })[vim_item.kind]
            return vim_item
        end,
        snippet = {
            expand = function(args)
                vim.fn["vsnip#anonymous"](args.body)
            end
        },
    },
})

@acicco Thanks! I have tried that aswell, see above

bangedorrunt commented 3 years ago

I think you could try remove packer compiled file and run PackerSync again

bragmore commented 3 years ago

I got this fixed by installing friendly-snippets, but it should work with just LSP too, removed packer compiled file and ran PackerSync without results.

ibhagwan commented 3 years ago

Just FYI, if anyone finds this thread and would like to use nvim-cmp without a snippet engine, I use the below, I found @Iron-E's snippet.expand but I was having issues with it, cursor was going to start of the replaced text and it would replace the entire line instead of just the completed text, the below works great for me: Forget it this is crap lol, I need to find another solution

Scroll two comments down for my actual solution

Iron-E commented 3 years ago

That's better. Thanks!


Edit: I was having issues where if the snippet was expanded before any other word (e.g. ^\t\tfor) it would snap back to the beginning of the line.

As such I fixed my solution above in an edit. Let me know if anyone has any other issues

ibhagwan commented 3 years ago

That's better. Thanks!

Edit: I was having issues where if the snippet was expanded before any other word (e.g. ^\t\tfor) it would snap back to the beginning of the line.

As such I fixed my solution above in an edit. Let me know if anyone has any other issues

Your solution fails me when my completion is not new text at the end of the line, if you're trying to complete text in the middle of the line the selected completion gets added at the end of the line and not in the right location.

This is the new solution I came up with, still in testing:

Edit: Only worked for one line completions (no idea why the count as snippets...), I had to add the code from @Iron-E to make it work for the actual snippets too (the ones with ~ at the end)

  snippet = {
    expand = function(args)
      local _, lnum, col, _ = unpack(vim.fn.getpos("."))
      local ltext = vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, true)[1]
      if args.body:match('\n') ~= nil then
        local indent = string.match(ltext, '^%s*')
        local lines = vim.split(args.body, '\n', true)
        lines[1] = (string.match(ltext, '%S.*') or '')..lines[1]
        if indent ~= '' then
          for i, line in ipairs(lines) do
              lines[i] = indent..line
          end
        end
        vim.api.nvim_buf_set_lines(0, lnum - 1, lnum, true, lines)
      else
        local line = ltext:sub(1, col-1) .. args.body .. ltext:sub(col)
        vim.api.nvim_buf_set_lines(0, lnum - 1, lnum, true, {line})
      end
      vim.api.nvim_win_set_cursor(0, {lnum, col+#args.body})
    end,
  },
Iron-E commented 3 years ago

Hey, thanks for letting me know! I'll split by cursor as well

Edit: fixed