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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
sudo apt install g++ gcc
sudo apt install g++ gcc
sudo apt install g++ gcc

Install clangd

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
sudo apt-get install clangd-12
sudo update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-12 100
sudo apt-get install clangd-12 sudo update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-12 100
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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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'
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'
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.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
mkdir -p ~/.config/nvim/lua/lsp/
touch ~/.config/nvim/lua/cpp.lua
mkdir -p ~/.config/nvim/lua/lsp/ touch ~/.config/nvim/lua/cpp.lua
mkdir -p ~/.config/nvim/lua/lsp/
touch ~/.config/nvim/lua/cpp.lua

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
-- 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/" },
})
-- 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/" }, })
-- 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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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>
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>
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: