local ok, cmp = pcall(require, "cmp") if not ok then return end local luasnip_ok, luasnip = pcall(require, "luasnip") if not luasnip_ok then return end local luasnip_vscode_ok, luasnip_vscode = pcall(require, "luasnip/loaders/from_vscode") if not luasnip_vscode_ok then return end local has_words_before = function() unpack = unpack or table.unpack local line, col = unpack(vim.api.nvim_win_get_cursor(0)) return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil end luasnip_vscode.lazy_load() cmp.setup({ view = { --entries = { name = "custom", selection_order = "near_cursor" }, }, snippet = { expand = function(args) luasnip.lsp_expand(args.body) -- For `luasnip` users. end, }, mapping = { [""] = cmp.mapping.confirm({ select = true }), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_next_item() -- You could replace the expand_or_jumpable() calls with expand_or_locally_jumpable() -- they way you will only jump inside the snippet region elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump() elseif has_words_before() then cmp.complete() else fallback() end end, { "i", "s" }), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_prev_item() elseif luasnip.jumpable(-1) then luasnip.jump(-1) else fallback() end end, { "i", "s" }), }, sources = { { name = "nvim_lsp" }, { name = "luasnip" }, { name = "buffer" }, { name = "path" }, }, confirm_opts = { behavior = cmp.ConfirmBehavior.Replace, select = false, }, experimental = { ghost_text = false, }, formatting = { fields = { "kind", "abbr", "menu" }, format = function(entry, vim_item) local lk_ok, lspkind = pcall(require, "lspkind") if not lk_ok then return end local kind = lspkind.cmp_format({ mode = "symbol_text", maxwidth = 50 })(entry, vim_item) local strings = vim.split(kind.kind, "%s", { trimempty = true }) kind.kind = " " .. (strings[1] or "") .. " " kind.menu = " (" .. (strings[2] or "") .. ")" return kind end, }, })