nvim: Refactor completion plugins

Begin a larger refactor with nvim-cmp, which separates out the different
nvim-cmp modules to be loaded at different times and for different files
(such as beancount completion on loaded for beancount files and so on).
This is by no means complete but the start of a larger overhaul process.
This commit is contained in:
Marty Oehme 2024-08-14 23:12:55 +02:00
parent 7723f43a5b
commit 3e369ee31e
Signed by: Marty
GPG key ID: EDBF2ED917B2EF6A

View file

@ -1,53 +1,29 @@
return { local completion_engine = {
-- completion setup
{ {
"hrsh7th/nvim-cmp", "hrsh7th/nvim-cmp",
branch = "main", branch = "main",
version = false, version = false, -- new releases (>2022) are sadly not versioned
dependencies = { dependencies = {
"andersevenrud/cmp-tmux", -- TODO: Move to lsp
"cbarrete/completion-vcard",
"f3fora/cmp-spell",
"hrsh7th/cmp-nvim-lsp", "hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-nvim-lsp-signature-help",
"hrsh7th/cmp-path", "hrsh7th/cmp-path",
"hrsh7th/cmp-buffer", "hrsh7th/cmp-buffer",
"hrsh7th/cmp-calc", "hrsh7th/cmp-calc",
"hrsh7th/cmp-cmdline", "hrsh7th/cmp-cmdline",
"hrsh7th/cmp-nvim-lsp-signature-help", -- TODO: Move me into a separate load?
"dmitmel/cmp-digraphs", "cbarrete/completion-vcard",
"f3fora/cmp-spell",
"jc-doyle/cmp-pandoc-references", "jc-doyle/cmp-pandoc-references",
"kdheepak/cmp-latex-symbols", -- TODO: Decide: get rid or just enable in very specific circumstances
"lukas-reineke/cmp-rg", "lukas-reineke/cmp-rg",
"crispgm/cmp-beancount", -- TODO: Move to treesitter
{ "ray-x/cmp-treesitter", dependencies = { "nvim-treesitter/nvim-treesitter" } }, { "ray-x/cmp-treesitter", dependencies = { "nvim-treesitter/nvim-treesitter" } },
{
"saadparwaiz1/cmp_luasnip",
dependencies = {
{
"L3MON4D3/LuaSnip",
dependencies = {
"rafamadriz/friendly-snippets",
{
"benfowler/telescope-luasnip.nvim",
dependencies = { { "nvim-telescope/telescope.nvim", optional = true } },
config = function()
require("telescope").load_extension("luasnip")
end,
},
},
build = "make install_jsregexp",
config = function()
require("luasnip.loaders.from_vscode").lazy_load({ exclude = { "markdown", "quarto" } })
require("luasnip.loaders.from_snipmate").lazy_load()
end,
},
},
},
}, },
config = function() opts = function()
local luasnip = require("luasnip")
local cmp = require("cmp") local cmp = require("cmp")
-- style 'ghosttext' which appears behind cursor, showing current completion
vim.api.nvim_set_hl(0, "CmpGhostText", { link = "Comment", default = true })
local has_words_before = function() local has_words_before = function()
---@diagnostic disable-next-line:deprecated ---@diagnostic disable-next-line:deprecated
@ -84,32 +60,42 @@ return {
TypeParameter = "", TypeParameter = "",
} }
cmp.setup({ -- `/` cmdline setup.
cmp.setup.cmdline("/", {
completion = { completeopt = "menu,menuone,noinsert,noselect" },
preselect = cmp.PreselectMode.None,
mapping = cmp.mapping.preset.cmdline(),
sources = { { name = "buffer" } },
})
-- `:` cmdline setup.
cmp.setup.cmdline(":", {
completion = { completeopt = "menu,menuone,noinsert,noselect" },
preselect = cmp.PreselectMode.None,
mapping = cmp.mapping.preset.cmdline(),
sources = cmp.config.sources({ { name = "path" } }, {
{ name = "cmdline", option = { ignore_cmds = { "Man", "!" } } },
}),
})
return {
window = { documentation = cmp.config.window.bordered() }, window = { documentation = cmp.config.window.bordered() },
snippet = { -- add noselect to not automatically select first item
expand = function(args) completion = { completeopt = "menu,menuone,noinsert" },
require("luasnip").lsp_expand(args.body) preselect = cmp.PreselectMode.Item, -- not sure what this changes diff than above?
end, experimental = {
ghost_text = {
hl_group = "CmpGhostText",
},
}, },
sources = { sources = {
{
name = "beancount",
option = {
account = vim.env["HOME"] .. "/documents/records/budget/main.beancount", -- TODO implement dynamically
},
},
{ name = "nvim_lsp" }, { name = "nvim_lsp" },
{ name = "nvim_lsp_signature_help" }, { name = "nvim_lsp_signature_help" },
{ name = "luasnip", keyword_length = 1 },
{ name = "pandoc_references" }, { name = "pandoc_references" },
{ name = "calc" }, { name = "calc" },
{ name = "path" }, { name = "path" },
{ name = "buffer", keyword_length = 3 }, { name = "buffer", keyword_length = 3 },
{ name = "latex_symbols" },
{ name = "spell", keyword_length = 3 }, { name = "spell", keyword_length = 3 },
{ name = "tmux" }, -- { name = 'rg', keyword_length = 5 }, -- { name = 'rg', keyword_length = 5 },
{ name = "vCard" }, { name = "vCard" },
{ name = "digraphs", keyword_length = 2 },
}, },
mapping = cmp.mapping.preset.insert({ mapping = cmp.mapping.preset.insert({
["<C-b>"] = cmp.mapping.scroll_docs(-4), ["<C-b>"] = cmp.mapping.scroll_docs(-4),
@ -134,9 +120,7 @@ return {
["<Tab>"] = cmp.mapping(function(fallback) ["<Tab>"] = cmp.mapping(function(fallback)
-- expand_or_jumpable() will always jump -- expand_or_jumpable() will always jump
-- expand_or_locally_jumpable() only jumps when still inside snippet region -- expand_or_locally_jumpable() only jumps when still inside snippet region
if luasnip.expand_or_locally_jumpable() then if cmp.visible() then
luasnip.expand_or_jump()
elseif cmp.visible() then
cmp.select_next_item() cmp.select_next_item()
elseif has_words_before() then elseif has_words_before() then
cmp.complete() cmp.complete()
@ -145,9 +129,7 @@ return {
end end
end, { "i", "s" }), end, { "i", "s" }),
["<S-Tab>"] = cmp.mapping(function(fallback) ["<S-Tab>"] = cmp.mapping(function(fallback)
if luasnip.jumpable(-1) then if cmp.visible() then
luasnip.jump(-1)
elseif cmp.visible() then
cmp.select_prev_item() cmp.select_prev_item()
else else
fallback() fallback()
@ -178,20 +160,111 @@ return {
return vim_item return vim_item
end, end,
}, },
}) }
-- `/` 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, end,
event = { "InsertEnter", "CmdlineEnter" }, event = { "InsertEnter", "CmdlineEnter" },
}, },
} }
--
-- TODO: Enable more lazy loaded startup? And integrate into
-- cmp as insert source instead of in its setup config below.
local snippet_engine = {
"nvim-cmp",
dependencies = {
"L3MON4D3/LuaSnip",
"rafamadriz/friendly-snippets",
"saadparwaiz1/cmp_luasnip",
{
"benfowler/telescope-luasnip.nvim",
dependencies = { { "nvim-telescope/telescope.nvim", optional = true } },
config = function()
if require("core.util").is_available("telescope") then
require("telescope").load_extension("luasnip")
end
end,
},
},
event = { "InsertEnter" },
build = "make install_jsregexp",
opts = function(_, opts)
local cmp = require("cmp")
local luasnip = require("luasnip")
require("luasnip.loaders.from_vscode").lazy_load({ exclude = { "markdown", "quarto" } })
require("luasnip.loaders.from_snipmate").lazy_load()
opts.snippet = {
expand = function(item)
require("luasnip").lsp_expand(item.body)
end,
}
local has_words_before = function()
---@diagnostic disable-next-line:deprecated
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
table.insert(opts.sources, { name = "luasnip", keyword_length = 1 })
opts.mapping["<Tab>"] = cmp.mapping(function(fallback) -- expand_or_jumpable() will always jump
-- expand_or_locally_jumpable() only jumps when still inside snippet region
if luasnip.expand_or_locally_jumpable() then
luasnip.expand_or_jump()
elseif cmp.visible() then
cmp.select_next_item()
elseif has_words_before() then
cmp.complete()
else
fallback()
end
end, { "i", "s" })
opts.mapping["<S-Tab>"] = cmp.mapping(function(fallback)
if luasnip.locally_jumpable(-1) then
luasnip.jump(-1)
elseif cmp.visible() then
cmp.select_prev_item()
else
fallback()
end
end, { "i", "s" })
end,
}
local beancount_cmp = {
"nvim-cmp",
dependencies = {
"crispgm/cmp-beancount",
},
ft = "beancount",
opts = function(_, opts)
vim.g.python3_host_prog = "/home/marty/.local/pipx/venvs/beancount/bin/python"
table.insert(opts.sources, {
name = "beancount",
-- option = {
-- -- TODO: implement dynamically
-- -- I believe if we don't supply this it automatically takes
-- -- from the open file which would be good enough
-- account = "/home/marty/documents/records/budget/main.beancount",
-- },
})
end,
}
local latex_cmp = {
"nvim-cmp",
dependencies = {
-- TODO: Needs better lazy loading
"kdheepak/cmp-latex-symbols",
},
event = "CursorHold",
opts = function(_, opts)
table.insert(opts.sources, { name = "latex_symbols" })
end,
}
return {
completion_engine,
snippet_engine,
beancount_cmp,
latex_cmp
}