Skip to content

Commit 581fae4

Browse files
committed
feat(completion): add nvim-cmp
1 parent 28eb977 commit 581fae4

File tree

2 files changed

+248
-0
lines changed

2 files changed

+248
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# nvim-cmp
2+
3+
A completion plugin for neovim coded in Lua.
4+
5+
**Repository:** <https://github.com/hrsh7th/nvim-cmp>
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
local function has_words_before()
2+
local line, col = (unpack or table.unpack)(vim.api.nvim_win_get_cursor(0))
3+
return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match "%s" == nil
4+
end
5+
local function is_visible(cmp) return cmp.core.view:visible() or vim.fn.pumvisible() == 1 end
6+
7+
return {
8+
"hrsh7th/nvim-cmp",
9+
dependencies = {
10+
{ "hrsh7th/cmp-buffer", lazy = true },
11+
{ "hrsh7th/cmp-path", lazy = true },
12+
{ "hrsh7th/cmp-nvim-lsp", lazy = true },
13+
},
14+
event = "InsertEnter",
15+
opts_extend = { "sources" },
16+
opts = function(_, opts)
17+
local cmp, astro = require "cmp", require "astrocore"
18+
19+
local sources = {}
20+
for source_plugin, source in pairs {
21+
["cmp-buffer"] = { name = "buffer", priority = 500, group_index = 2 },
22+
["cmp-nvim-lsp"] = { name = "nvim_lsp", priority = 1000 },
23+
["cmp-path"] = { name = "path", priority = 250 },
24+
} do
25+
if astro.is_available(source_plugin) then table.insert(sources, source) end
26+
end
27+
28+
local function get_icon_provider()
29+
local _, mini_icons = pcall(require, "mini.icons")
30+
if _G.MiniIcons then
31+
return function(kind) return mini_icons.get("lsp", kind or "") end
32+
end
33+
local lspkind_avail, lspkind = pcall(require, "lspkind")
34+
if lspkind_avail then
35+
return function(kind) return lspkind.symbolic(kind, { mode = "symbol" }) end
36+
end
37+
end
38+
local icon_provider = get_icon_provider()
39+
40+
local function format(entry, item)
41+
local highlight_colors_avail, highlight_colors = pcall(require, "nvim-highlight-colors")
42+
local color_item = highlight_colors_avail and highlight_colors.format(entry, { kind = item.kind })
43+
if icon_provider then
44+
local icon = icon_provider(item.kind)
45+
if icon then item.kind = icon end
46+
end
47+
if color_item and color_item.abbr and color_item.abbr_hl_group then
48+
item.kind, item.kind_hl_group = color_item.abbr, color_item.abbr_hl_group
49+
end
50+
return item
51+
end
52+
53+
return astro.extend_tbl(opts, {
54+
enabled = function()
55+
-- Disable completion when recording macros
56+
if vim.fn.reg_recording() ~= "" or vim.fn.reg_executing() ~= "" then return false end
57+
-- Disable completion for prompt windows that are not `nvim-dap` prompts
58+
local dap_prompt = astro.is_available "cmp-dap" -- add interoperability with cmp-dap
59+
and vim.tbl_contains({ "dap-repl", "dapui_watches", "dapui_hover" }, vim.bo.filetype)
60+
if vim.bo.buftype == "prompt" and not dap_prompt then return false end
61+
-- Disable completion when disabled in AstroNvim
62+
return vim.F.if_nil(vim.b.completion, astro.config.features.cmp)
63+
end,
64+
preselect = cmp.PreselectMode.None,
65+
formatting = { fields = { "kind", "abbr", "menu" }, format = format },
66+
confirm_opts = {
67+
behavior = cmp.ConfirmBehavior.Replace,
68+
select = false,
69+
},
70+
window = {
71+
completion = cmp.config.window.bordered {
72+
col_offset = -2,
73+
side_padding = 0,
74+
border = "rounded",
75+
winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder,CursorLine:PmenuSel,Search:None",
76+
},
77+
documentation = cmp.config.window.bordered {
78+
border = "rounded",
79+
winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder,CursorLine:PmenuSel,Search:None",
80+
},
81+
},
82+
mapping = {
83+
["<Up>"] = cmp.mapping.select_prev_item { behavior = cmp.SelectBehavior.Select },
84+
["<Down>"] = cmp.mapping.select_next_item { behavior = cmp.SelectBehavior.Select },
85+
["<C-P>"] = cmp.mapping(function()
86+
if is_visible(cmp) then
87+
cmp.select_prev_item()
88+
else
89+
cmp.complete()
90+
end
91+
end),
92+
["<C-N>"] = cmp.mapping(function()
93+
if is_visible(cmp) then
94+
cmp.select_next_item()
95+
else
96+
cmp.complete()
97+
end
98+
end),
99+
["<C-K>"] = cmp.mapping(cmp.mapping.select_prev_item(), { "i", "c" }),
100+
["<C-J>"] = cmp.mapping(cmp.mapping.select_next_item(), { "i", "c" }),
101+
["<C-U>"] = cmp.mapping(cmp.mapping.scroll_docs(-4), { "i", "c" }),
102+
["<C-D>"] = cmp.mapping(cmp.mapping.scroll_docs(4), { "i", "c" }),
103+
["<C-Space>"] = cmp.mapping(cmp.mapping.complete(), { "i", "c" }),
104+
["<C-Y>"] = cmp.config.disable,
105+
["<C-E>"] = cmp.mapping(cmp.mapping.abort(), { "i", "c" }),
106+
["<CR>"] = cmp.mapping(cmp.mapping.confirm { select = false }, { "i", "c" }),
107+
["<Tab>"] = cmp.mapping(function(fallback)
108+
if is_visible(cmp) then
109+
cmp.select_next_item()
110+
elseif vim.api.nvim_get_mode().mode ~= "c" and vim.snippet and vim.snippet.active { direction = 1 } then
111+
vim.schedule(function() vim.snippet.jump(1) end)
112+
elseif has_words_before() then
113+
cmp.complete()
114+
else
115+
fallback()
116+
end
117+
end, { "i", "s" }),
118+
["<S-Tab>"] = cmp.mapping(function(fallback)
119+
if is_visible(cmp) then
120+
cmp.select_prev_item()
121+
elseif vim.api.nvim_get_mode().mode ~= "c" and vim.snippet and vim.snippet.active { direction = -1 } then
122+
vim.schedule(function() vim.snippet.jump(-1) end)
123+
else
124+
fallback()
125+
end
126+
end, { "i", "s" }),
127+
},
128+
sources = sources,
129+
})
130+
end,
131+
config = function(_, opts)
132+
for _, source in ipairs(opts.sources or {}) do
133+
if not source.group_index then source.group_index = 1 end
134+
end
135+
local cmp = require "cmp"
136+
cmp.setup(opts)
137+
138+
local autopairs_avail, autopairs = pcall(require, "nvim-autopairs.completion.cmp")
139+
if autopairs_avail then cmp.event:on("confirm_done", autopairs.on_confirm_done { tex = false }) end
140+
end,
141+
specs = {
142+
{
143+
"AstroNvim/astrolsp",
144+
optional = true,
145+
opts = function(_, opts)
146+
local astrocore = require "astrocore"
147+
if astrocore.is_available "cmp-nvim-lsp" then
148+
opts.capabilities = astrocore.extend_tbl(opts.capabilities, {
149+
textDocument = {
150+
completion = {
151+
completionItem = {
152+
documentationFormat = { "markdown", "plaintext" },
153+
snippetSupport = true,
154+
preselectSupport = true,
155+
insertReplaceSupport = true,
156+
labelDetailsSupport = true,
157+
deprecatedSupport = true,
158+
commitCharactersSupport = true,
159+
tagSupport = { valueSet = { 1 } },
160+
resolveSupport = { properties = { "documentation", "detail", "additionalTextEdits" } },
161+
},
162+
},
163+
},
164+
})
165+
end
166+
end,
167+
},
168+
{
169+
"AstroNvim/astrocore",
170+
opts = function(_, opts)
171+
local maps = opts.mappings
172+
maps.n["<Leader>uc"] =
173+
{ function() require("astrocore.toggles").buffer_cmp() end, desc = "Toggle autocompletion (buffer)" }
174+
maps.n["<Leader>uC"] =
175+
{ function() require("astrocore.toggles").cmp() end, desc = "Toggle autocompletion (global)" }
176+
end,
177+
},
178+
{
179+
"L3MON4D3/LuaSnip",
180+
optional = true,
181+
specs = {
182+
{
183+
"hrsh7th/nvim-cmp",
184+
dependencies = { { "saadparwaiz1/cmp_luasnip", lazy = true } },
185+
opts = function(_, opts)
186+
local luasnip, cmp = require "luasnip", require "cmp"
187+
188+
if not opts.snippet then opts.snippet = {} end
189+
opts.snippet.expand = function(args) luasnip.lsp_expand(args.body) end
190+
191+
if not opts.sources then opts.sources = {} end
192+
table.insert(opts.sources, { name = "luasnip", priority = 750 })
193+
194+
if not opts.mappings then opts.mappings = {} end
195+
opts.mapping["<Tab>"] = cmp.mapping(function(fallback)
196+
if is_visible(cmp) then
197+
cmp.select_next_item()
198+
elseif vim.api.nvim_get_mode().mode ~= "c" and luasnip.expand_or_locally_jumpable() then
199+
luasnip.expand_or_jump()
200+
elseif has_words_before() then
201+
cmp.complete()
202+
else
203+
fallback()
204+
end
205+
end, { "i", "s" })
206+
opts.mapping["<S-Tab>"] = cmp.mapping(function(fallback)
207+
if is_visible(cmp) then
208+
cmp.select_prev_item()
209+
elseif vim.api.nvim_get_mode().mode ~= "c" and luasnip.jumpable(-1) then
210+
luasnip.jump(-1)
211+
else
212+
fallback()
213+
end
214+
end, { "i", "s" })
215+
end,
216+
},
217+
},
218+
},
219+
{
220+
"folke/lazydev.nvim",
221+
optional = true,
222+
specs = {
223+
{
224+
"hrsh7th/nvim-cmp",
225+
opts = function(_, opts) table.insert(opts.sources, { name = "lazydev", group_index = 0 }) end,
226+
},
227+
},
228+
},
229+
{
230+
"rcarriga/cmp-dap",
231+
optional = true,
232+
dependencies = { "hrsh7th/nvim-cmp" },
233+
config = function(...)
234+
require "astronvim.plugins.configs.cmp-dap"(...)
235+
require("cmp").setup.filetype({ "dap-repl", "dapui_watches", "dapui_hover" }, {
236+
sources = {
237+
{ name = "dap" },
238+
},
239+
})
240+
end,
241+
},
242+
},
243+
}

0 commit comments

Comments
 (0)