From eeb0c4a236706b3534e2843ff9804e4bf2483b6b Mon Sep 17 00:00:00 2001 From: Robin Gruyters <2082795+rgruyters@users.noreply.github.com> Date: Fri, 28 Mar 2025 17:29:03 +0100 Subject: [PATCH] chore(lsp.completion): first attempt for native lsp completion --- init.lua | 324 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 205 insertions(+), 119 deletions(-) diff --git a/init.lua b/init.lua index cbf9ff65..882a3ed3 100644 --- a/init.lua +++ b/init.lua @@ -487,7 +487,7 @@ require('lazy').setup({ { 'j-hui/fidget.nvim', opts = {} }, -- Allows extra capabilities provided by nvim-cmp - 'hrsh7th/cmp-nvim-lsp', + -- 'hrsh7th/cmp-nvim-lsp', }, config = function() -- Brief aside: **What is LSP?** @@ -623,6 +623,92 @@ require('lazy').setup({ end, }) + vim.api.nvim_create_autocmd('LspAttach', { + group = vim.api.nvim_create_augroup('kickstart-lsp-completion', { clear = true }), + callback = function(event) + local function keymap(lhs, rhs, opts, mode) + opts = type(opts) == 'string' and { desc = opts } or vim.tbl_extend('error', opts --[[@as table]], { buffer = event.buf }) + mode = mode or 'n' + vim.keymap.set(mode, lhs, rhs, opts) + end + + local function feedkeys(keys) + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(keys, true, false, true), 'n', true) + end + + ---Is the completion menu open? + local function pumvisible() + return tonumber(vim.fn.pumvisible()) ~= 0 + end + + local client = vim.lsp.get_client_by_id(event.data.client_id) + if client and client:supports_method 'textDocument/completion' then + vim.lsp.completion.enable(true, client.id, event.buf, { autotrigger = true }) + + -- Use enter to accept completions. + keymap('', function() + return pumvisible() and '' or '' + end, { expr = true }, 'i') + + -- Use slash to dismiss the completion menu. + keymap('/', function() + return pumvisible() and '' or '/' + end, { expr = true }, 'i') + + -- Use to navigate to the next completion or: + -- - Trigger LSP completion. + -- - If there's no one, fallback to vanilla omnifunc. + keymap('', function() + if pumvisible() then + feedkeys '' + else + if next(vim.lsp.get_clients { bufnr = 0 }) then + vim.lsp.completion.trigger() + else + if vim.bo.omnifunc == '' then + feedkeys '' + else + feedkeys '' + end + end + end + end, 'Trigger/select next completion', 'i') + + -- Buffer completions. + keymap('', '', { desc = 'Buffer completions' }, 'i') + + -- Use to accept a Copilot suggestion, navigate between snippet tabstops, + -- or select the next completion. + -- Do something similar with . + keymap('', function() + local copilot = require 'copilot.suggestion' + + if copilot.is_visible() then + copilot.accept() + elseif pumvisible() then + feedkeys '' + elseif vim.snippet.active { direction = 1 } then + vim.snippet.jump(1) + else + feedkeys '' + end + end, {}, { 'i', 's' }) + keymap('', function() + if pumvisible() then + feedkeys '' + elseif vim.snippet.active { direction = -1 } then + vim.snippet.jump(-1) + else + feedkeys '' + end + end, {}, { 'i', 's' }) + + -- Inside a snippet, use backspace to remove the placeholder. + keymap('', 's', {}, 's') + end + end, + }) + -- Diagnostic Config -- See :help vim.diagnostic.Opts vim.diagnostic.config { @@ -657,7 +743,7 @@ require('lazy').setup({ -- When you add nvim-cmp, luasnip, etc. Neovim now has *more* capabilities. -- So, we create new capabilities with nvim cmp, and then broadcast that to the servers. local capabilities = vim.lsp.protocol.make_client_capabilities() - capabilities = vim.tbl_deep_extend('force', capabilities, require('cmp_nvim_lsp').default_capabilities()) + -- capabilities = vim.tbl_deep_extend('force', capabilities, require('cmp_nvim_lsp').default_capabilities()) -- Enable the following language servers -- Feel free to add/remove any LSPs that you want here. They will automatically be installed. @@ -775,123 +861,123 @@ require('lazy').setup({ }, }, - { -- Autocompletion - 'hrsh7th/nvim-cmp', - event = 'InsertEnter', - dependencies = { - -- Snippet Engine & its associated nvim-cmp source - { - 'L3MON4D3/LuaSnip', - build = (function() - -- Build Step is needed for regex support in snippets. - -- This step is not supported in many windows environments. - -- Remove the below condition to re-enable on windows. - if vim.fn.has 'win32' == 1 or vim.fn.executable 'make' == 0 then - return - end - return 'make install_jsregexp' - end)(), - dependencies = { - -- `friendly-snippets` contains a variety of premade snippets. - -- See the README about individual language/framework/plugin snippets: - -- https://github.com/rafamadriz/friendly-snippets - -- { - -- 'rafamadriz/friendly-snippets', - -- config = function() - -- require('luasnip.loaders.from_vscode').lazy_load() - -- end, - -- }, - }, - }, - 'saadparwaiz1/cmp_luasnip', - - -- Adds other completion capabilities. - -- nvim-cmp does not ship with all sources by default. They are split - -- into multiple repos for maintenance purposes. - 'hrsh7th/cmp-nvim-lsp', - 'hrsh7th/cmp-path', - 'hrsh7th/cmp-nvim-lsp-signature-help', - }, - config = function() - -- See `:help cmp` - local cmp = require 'cmp' - local luasnip = require 'luasnip' - luasnip.config.setup {} - - cmp.setup { - snippet = { - expand = function(args) - luasnip.lsp_expand(args.body) - end, - }, - completion = { completeopt = 'menu,menuone,noinsert' }, - - -- For an understanding of why these mappings were - -- chosen, you will need to read `:help ins-completion` - -- - -- No, but seriously. Please read `:help ins-completion`, it is really good! - mapping = cmp.mapping.preset.insert { - -- Select the [n]ext item - [''] = cmp.mapping.select_next_item(), - -- Select the [p]revious item - [''] = cmp.mapping.select_prev_item(), - - -- Scroll the documentation window [b]ack / [f]orward - [''] = cmp.mapping.scroll_docs(-4), - [''] = cmp.mapping.scroll_docs(4), - - -- Accept ([y]es) the completion. - -- This will auto-import if your LSP supports it. - -- This will expand snippets if the LSP sent a snippet. - [''] = cmp.mapping.confirm { select = true }, - - -- If you prefer more traditional completion keymaps, - -- you can uncomment the following lines - --[''] = cmp.mapping.confirm { select = true }, - --[''] = cmp.mapping.select_next_item(), - --[''] = cmp.mapping.select_prev_item(), - - -- Manually trigger a completion from nvim-cmp. - -- Generally you don't need this, because nvim-cmp will display - -- completions whenever it has completion options available. - [''] = cmp.mapping.complete {}, - - -- Think of as moving to the right of your snippet expansion. - -- So if you have a snippet that's like: - -- function $name($args) - -- $body - -- end - -- - -- will move you to the right of each of the expansion locations. - -- is similar, except moving you backwards. - [''] = cmp.mapping(function() - if luasnip.expand_or_locally_jumpable() then - luasnip.expand_or_jump() - end - end, { 'i', 's' }), - [''] = cmp.mapping(function() - if luasnip.locally_jumpable(-1) then - luasnip.jump(-1) - end - end, { 'i', 's' }), - - -- For more advanced Luasnip keymaps (e.g. selecting choice nodes, expansion) see: - -- https://github.com/L3MON4D3/LuaSnip?tab=readme-ov-file#keymaps - }, - sources = { - { - name = 'lazydev', - -- set group index to 0 to skip loading LuaLS completions as lazydev recommends it - group_index = 0, - }, - { name = 'nvim_lsp' }, - { name = 'luasnip' }, - { name = 'path' }, - { name = 'nvim_lsp_signature_help' }, - }, - } - end, - }, + -- { -- Autocompletion + -- 'hrsh7th/nvim-cmp', + -- event = 'InsertEnter', + -- dependencies = { + -- -- Snippet Engine & its associated nvim-cmp source + -- { + -- 'L3MON4D3/LuaSnip', + -- build = (function() + -- -- Build Step is needed for regex support in snippets. + -- -- This step is not supported in many windows environments. + -- -- Remove the below condition to re-enable on windows. + -- if vim.fn.has 'win32' == 1 or vim.fn.executable 'make' == 0 then + -- return + -- end + -- return 'make install_jsregexp' + -- end)(), + -- dependencies = { + -- -- `friendly-snippets` contains a variety of premade snippets. + -- -- See the README about individual language/framework/plugin snippets: + -- -- https://github.com/rafamadriz/friendly-snippets + -- -- { + -- -- 'rafamadriz/friendly-snippets', + -- -- config = function() + -- -- require('luasnip.loaders.from_vscode').lazy_load() + -- -- end, + -- -- }, + -- }, + -- }, + -- 'saadparwaiz1/cmp_luasnip', + -- + -- -- Adds other completion capabilities. + -- -- nvim-cmp does not ship with all sources by default. They are split + -- -- into multiple repos for maintenance purposes. + -- 'hrsh7th/cmp-nvim-lsp', + -- 'hrsh7th/cmp-path', + -- 'hrsh7th/cmp-nvim-lsp-signature-help', + -- }, + -- config = function() + -- -- See `:help cmp` + -- local cmp = require 'cmp' + -- local luasnip = require 'luasnip' + -- luasnip.config.setup {} + -- + -- cmp.setup { + -- snippet = { + -- expand = function(args) + -- luasnip.lsp_expand(args.body) + -- end, + -- }, + -- completion = { completeopt = 'menu,menuone,noinsert' }, + -- + -- -- For an understanding of why these mappings were + -- -- chosen, you will need to read `:help ins-completion` + -- -- + -- -- No, but seriously. Please read `:help ins-completion`, it is really good! + -- mapping = cmp.mapping.preset.insert { + -- -- Select the [n]ext item + -- [''] = cmp.mapping.select_next_item(), + -- -- Select the [p]revious item + -- [''] = cmp.mapping.select_prev_item(), + -- + -- -- Scroll the documentation window [b]ack / [f]orward + -- [''] = cmp.mapping.scroll_docs(-4), + -- [''] = cmp.mapping.scroll_docs(4), + -- + -- -- Accept ([y]es) the completion. + -- -- This will auto-import if your LSP supports it. + -- -- This will expand snippets if the LSP sent a snippet. + -- [''] = cmp.mapping.confirm { select = true }, + -- + -- -- If you prefer more traditional completion keymaps, + -- -- you can uncomment the following lines + -- --[''] = cmp.mapping.confirm { select = true }, + -- --[''] = cmp.mapping.select_next_item(), + -- --[''] = cmp.mapping.select_prev_item(), + -- + -- -- Manually trigger a completion from nvim-cmp. + -- -- Generally you don't need this, because nvim-cmp will display + -- -- completions whenever it has completion options available. + -- [''] = cmp.mapping.complete {}, + -- + -- -- Think of as moving to the right of your snippet expansion. + -- -- So if you have a snippet that's like: + -- -- function $name($args) + -- -- $body + -- -- end + -- -- + -- -- will move you to the right of each of the expansion locations. + -- -- is similar, except moving you backwards. + -- [''] = cmp.mapping(function() + -- if luasnip.expand_or_locally_jumpable() then + -- luasnip.expand_or_jump() + -- end + -- end, { 'i', 's' }), + -- [''] = cmp.mapping(function() + -- if luasnip.locally_jumpable(-1) then + -- luasnip.jump(-1) + -- end + -- end, { 'i', 's' }), + -- + -- -- For more advanced Luasnip keymaps (e.g. selecting choice nodes, expansion) see: + -- -- https://github.com/L3MON4D3/LuaSnip?tab=readme-ov-file#keymaps + -- }, + -- sources = { + -- { + -- name = 'lazydev', + -- -- set group index to 0 to skip loading LuaLS completions as lazydev recommends it + -- group_index = 0, + -- }, + -- { name = 'nvim_lsp' }, + -- { name = 'luasnip' }, + -- { name = 'path' }, + -- { name = 'nvim_lsp_signature_help' }, + -- }, + -- } + -- end, + -- }, { -- You can easily change to a different colorscheme. -- Change the name of the colorscheme plugin below, and then