diff --git a/nvim/.config/nvim/lua/plugins/completion.lua b/nvim/.config/nvim/lua/plugins/completion.lua index e8dedd7..aaf31fc 100644 --- a/nvim/.config/nvim/lua/plugins/completion.lua +++ b/nvim/.config/nvim/lua/plugins/completion.lua @@ -1,53 +1,29 @@ -return { - -- completion setup +local completion_engine = { { "hrsh7th/nvim-cmp", branch = "main", - version = false, + version = false, -- new releases (>2022) are sadly not versioned dependencies = { - "andersevenrud/cmp-tmux", - "cbarrete/completion-vcard", - "f3fora/cmp-spell", + -- TODO: Move to lsp "hrsh7th/cmp-nvim-lsp", + "hrsh7th/cmp-nvim-lsp-signature-help", "hrsh7th/cmp-path", "hrsh7th/cmp-buffer", "hrsh7th/cmp-calc", "hrsh7th/cmp-cmdline", - "hrsh7th/cmp-nvim-lsp-signature-help", - "dmitmel/cmp-digraphs", + -- TODO: Move me into a separate load? + "cbarrete/completion-vcard", + "f3fora/cmp-spell", "jc-doyle/cmp-pandoc-references", - "kdheepak/cmp-latex-symbols", + -- TODO: Decide: get rid or just enable in very specific circumstances "lukas-reineke/cmp-rg", - "crispgm/cmp-beancount", + -- TODO: Move to 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() - local luasnip = require("luasnip") + opts = function() 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() ---@diagnostic disable-next-line:deprecated @@ -84,32 +60,42 @@ return { 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() }, - snippet = { - expand = function(args) - require("luasnip").lsp_expand(args.body) - end, + -- add noselect to not automatically select first item + completion = { completeopt = "menu,menuone,noinsert" }, + preselect = cmp.PreselectMode.Item, -- not sure what this changes diff than above? + experimental = { + ghost_text = { + hl_group = "CmpGhostText", + }, }, sources = { - { - name = "beancount", - option = { - account = vim.env["HOME"] .. "/documents/records/budget/main.beancount", -- TODO implement dynamically - }, - }, { name = "nvim_lsp" }, { name = "nvim_lsp_signature_help" }, - { name = "luasnip", keyword_length = 1 }, { name = "pandoc_references" }, { name = "calc" }, { name = "path" }, { name = "buffer", keyword_length = 3 }, - { name = "latex_symbols" }, { name = "spell", keyword_length = 3 }, - { name = "tmux" }, -- { name = 'rg', keyword_length = 5 }, + -- { name = 'rg', keyword_length = 5 }, { name = "vCard" }, - { name = "digraphs", keyword_length = 2 }, }, mapping = cmp.mapping.preset.insert({ [""] = cmp.mapping.scroll_docs(-4), @@ -134,9 +120,7 @@ return { [""] = 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 + if cmp.visible() then cmp.select_next_item() elseif has_words_before() then cmp.complete() @@ -145,9 +129,7 @@ return { end end, { "i", "s" }), [""] = cmp.mapping(function(fallback) - if luasnip.jumpable(-1) then - luasnip.jump(-1) - elseif cmp.visible() then + if cmp.visible() then cmp.select_prev_item() else fallback() @@ -178,20 +160,111 @@ return { return vim_item 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, 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[""] = 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[""] = 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 +}