TITLE: First setup for nvim-lsp with nvim-cmp
DATE: 2021-11-30
AUTHOR: John L. Godlee
====================================================================


I used to use ncm2 for autocompletion in neovim, then I switched to
coc.nvim for a short time, but found it awkward to maintain.
Recently I set up nvim-cmp, which uses neovim's built-in language
server client to source external language servers for different
languages.

 [ncm2]: https://github.com/ncm2/ncm2
 [neovim]: https://neovim.io/
 [coc.nvim]: https://github.com/neoclide/coc.nvim
 [nvim-cmp]: https://github.com/hrsh7th/nvim-cmp

I use auto-completion fairly sparingly, but I do find it incredibly
useful for two main things: completing file paths, and suggesting
snippets from Ultisnips. I also sometimes use language
auto-completion when writing R. Possibly in the future I'd also
like to use auto-completion for writing LaTeX, Javascript, Julia
and CSS, but for now I've just set up the language server for R.

 [Ultisnips]: https://github.com/SirVer/ultisnips

The R language server is installed by running
install.packages("languageserver") in R. I use the Nvim-R vim
plugin to turn neovim into something more like a full IDE. Nvim-R
provides syntax highlighting for R code, allows interaction with an
open R repl either in a tmux split or a nvim terminal buffer, among
many other features. I use radian to provide a smarter R repl.

 [Nvim-R]: https://github.com/jalvesaq/Nvim-R
 [radian]: https://github.com/randy3k/radian

To set up nvim-cmp I largely followed the example configuration
provided in the nvim-cmp README.md, but I've added an extra bit at
the end to disable buffer word completion in file types which
normally contain prose. I've pasted the config below for Nvim-R,
Ultisnips, and nvim-cmp.

I wish I understood a bit better what the different bits of lua
code actually do (e.g. the calls to cmp.setup.cmdline), but I found
the online documentation to be quite lacking.

 ![Screenshot demonstrating Nvim-R and
nvim-cmp](https://johngodlee.xyz/img_full/nvim_lsp/scrot.png)

   " Plugins
   call plug#begin('~/.vim/plugged')

   Plug 'SirVer/ultisnips' " Snippets
   Plug 'jalvesaq/Nvim-R'
   Plug 'neovim/nvim-lspconfig'
   Plug 'hrsh7th/cmp-nvim-lsp'
   Plug 'hrsh7th/cmp-path'
   Plug 'hrsh7th/cmp-buffer'
   Plug 'hrsh7th/cmp-cmdline'
   Plug 'hrsh7th/nvim-cmp'
   Plug 'quangnguyen30192/cmp-nvim-ultisnips'

   call plug#end()

   " nvim-cmp
   set completeopt=menuone,noselect

   lua <<EOF
     local cmp = require'cmp'

     -- Setup nvim-cmp
     cmp.setup({
       -- Specify snippet engine
       snippet = {
         expand = function(args)
           vim.fn["UltiSnips#Anon"](args.body)
         end,
       },
       -- Keybindings
       mapping = {
         ['<C-n>'] = cmp.mapping.select_next_item({ behavior =
cmp.SelectBehavior.Insert }),
         ['<C-p>'] = cmp.mapping.select_prev_item({ behavior =
cmp.SelectBehavior.Insert }),
         ['<Down>'] = cmp.mapping.select_next_item({ behavior =
cmp.SelectBehavior.Select }),
         ['<Up>'] = cmp.mapping.select_prev_item({ behavior =
cmp.SelectBehavior.Select }),
         ['<CR>'] = cmp.mapping.confirm({ select = true }),
       },
       -- Define completion sources
       sources = cmp.config.sources({
         { name = 'nvim_lsp' },
         { name = 'ultisnips' },
         { name = 'buffer' },
         { name = 'path' },
       })
     })

     cmp.setup.cmdline('/', {
       sources = {
         { name = 'buffer' }
       }
     })

     cmp.setup.cmdline(':', {
       sources = cmp.config.sources({
         { name = 'path' }
       }, {
         { name = 'cmdline' }
       })
     })

     -- Setup lspconfig
     local capabilities =
require('cmp_nvim_lsp').update_capabilities(vim.lsp.protocol.make_cl
ient_capabilities())

     -- R language server options
     require('lspconfig')['r_language_server'].setup {
       cmd = { "R", "--slave", "-e", "languageserver::run()" },
       filetypes = { "r", "rmd" }
     }

   EOF

   " Only enable minimal completion in files containing prose
   autocmd FileType markdown,tex,txt lua require'cmp'.setup.buffer
{
   \   sources = {
   \     { name = 'path' },
   \     { name = 'ultisnips' },
   \   },
   \ }

   " Nvim-R
   let R_external_term = 0
   let R_source = '~/.vim/tmux_split.vim'
   let R_assign = 0
   let R_objbr_place = 'BOTTOM'
   let R_objbr_h = 30
   let R_min_editor_width = 80
   let R_objbr_opendf = 0
   let r_indent_comment_column = 0
   let r_indent_align_args = 0
   let r_indent_ess_comments = 0
   let r_indent_ess_compatible = 0
   let R_non_r_compl = 0
   let R_rmdchunk = 0
   let R_rnowebchunk = 0
   let R_app = "radian"
   let R_cmd = "R"
   let R_hl_term = 0
   let R_args = []
   let R_bracketed_paste = 1

   nmap <LocalLeader><Enter> <Plug>RDSendLine
   vmap <LocalLeader><Enter> <Plug>REDSendSelection

   " Ultisnips
   let g:UltiSnipsExpandTrigger="<tab>"
   let g:UltiSnipsJumpForwardTrigger="<c-l>"
   let g:UltiSnipsJumpBackwardTrigger="<c-h>"
   let g:UltiSnipsEditSplit="vertical"
   let g:UltiSnipsSnippetDirectories=[$HOME.'/.vim/Ultisnips']

Update 2021-12-05

I spent about 3 days trying to work with nvim-cmp, but I found that
if I had more than two R scripts open in separate nvim instances,
the fans on my MacBook Pro would start going crazy and htop showed
the CPU maxed out. For me that’s not good enough, and I can get
by with the built-in completion provided by Ctrl-x Ctrl-f / ctrl-o
etc. So that’s a bit disappointing, and I’m not sure whether it
will ever get better. I see that nvim v0.60 has just been released,
but reading through the release notes I see no improvements to LSP
support. As an uninformed user it's difficult to know if the
bottleneck is nvim-cmp, the R language server, or nvim.