Set up Neovim LSP for C/C++

Install Neovim

This tutorial assumes you have Neovim installed. If that’s not the case, you can follow this tutorial for instructions.

Install compilers

sudo apt install g++ gcc

Install clangd

sudo apt-get install clangd-12
sudo update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-12 100

Install the plugins

NOTE: I’m using vim-plug for managing my [Neo]vim plugins.

The nvim-cmp plugin will do the magic, though it requires a few other plugins:

Plug 'neovim/nvim-lspconfig'

Plug 'hrsh7th/cmp-nvim-lsp'
Plug 'hrsh7th/cmp-buffer'
Plug 'hrsh7th/cmp-path'
Plug 'hrsh7th/cmp-cmdline'
Plug 'hrsh7th/nvim-cmp'

" For vsnip users.
Plug 'hrsh7th/cmp-vsnip'
Plug 'hrsh7th/vim-vsnip'

Configure the LSP client for C++

To keep things separate and tidy, let’s put all Lua config in separate files and import them from the main configuration file.

mkdir -p ~/.config/nvim/lua/lsp/
touch ~/.config/nvim/lua/cpp.lua

Put the following configuration in ~/.config/nvim/lua/cpp.lua:

-- Set up nvim-cmp.
local cmp = require'cmp'

cmp.setup({
    snippet = {
        -- REQUIRED - you must specify a snippet engine
        expand = function(args)
            vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.
        end,
    },
    window = {
        -- completion = cmp.config.window.bordered(),
        -- documentation = cmp.config.window.bordered(),
    },
    mapping = cmp.mapping.preset.insert({
        ['<C-b>'] = cmp.mapping.scroll_docs(-4),
        ['<C-f>'] = cmp.mapping.scroll_docs(4),
        ['<C-Space>'] = cmp.mapping.complete(),
        ['<C-e>'] = cmp.mapping.abort(),
        ['<CR>'] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
    }),
    sources = cmp.config.sources({
        { name = 'nvim_lsp' },
        { name = 'vsnip' }, -- For vsnip users.
    },  {{ name = 'buffer' }}
    )
})

-- Set configuration for specific filetype.
cmp.setup.filetype('gitcommit', {
    sources = cmp.config.sources({
        { name = 'git' }, -- You can specify the `git` source if [you were installed it](https://github.com/petertriho/cmp-git).
    }, {
        { name = 'buffer' },
    })
})

-- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore).
cmp.setup.cmdline({ '/', '?' }, {
    mapping = cmp.mapping.preset.cmdline(),
    sources = {
        { name = 'buffer' }
    }
})

-- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore).
cmp.setup.cmdline(':', {
    mapping = cmp.mapping.preset.cmdline(),
    sources = cmp.config.sources({
        { name = 'path' }
    }, {
        { name = 'cmdline' }
    })
})

-- Set up lspconfig.
local capabilities = require('cmp_nvim_lsp').default_capabilities()

-- Replace <YOUR_LSP_SERVER> with each lsp server you've enabled.
require'lspconfig'.clangd.setup({
    capabilities = capabilities,
	  -- The following line is OPTIONAL, it's used to modify how clangd works.
    cmd = { "clangd", "--compile-commands-dir=/home/username/.config/clangd/cpp/" },
})

Custom command (optional)

Create a file in /home/username/.config/clangd/cpp/ named compile_flags.txt with this content -std=c++17.

See the clangd documentation for more details if you’re interested.

Execute your program (optional)

The following Vim config will allow you to run your program with a single keystroke:

if filereadable("Makefile")
  setlocal makeprg=make
else
  setlocal makeprg=g++\ -Wall\ -std=c++17\ -o\ %<\ %
endif

function RunProgram()
    execute 'make'
    execute '!./%<'
endfunction

nnoremap <F12> :call RunProgram()<cr>
inoremap <F12> <Esc>:call RunProgram()<cr>

There you go, happy C/C++ coding in Neovim!


Posted

in

,

by

Tags: