I believe you can setup multiple servers, but I haven’t tried it. I used to switch back and forth between ccls and clangd until finally I’ve settled on clangd since v12.0 is much improved (it lacks snippets and a few gotos, but is fairly stable especially with the incremental_sync feature in nvim that’s being worked on right now). You mention you use ccls for completion, do you find its completion better than clangd’s?
I can answer your #2 question with my config for clangd SwitchSourceHeader.
Basically you just need to call vim.lsp.buf_request(bufnr, method, params, handler)
where bufnr is the buffer #, params contains the file uri, method is textDocument/switchSourceHeader
, and the handler is a callback function which will handle the response.
The callback function gets called once clangd responds, and it’s given the uri of the header/source file (or an err, if clangd can’t find it). There’s a helper function built-into vim to convert a uri to a filename, which is handy here. Then you can have your callback open the file by using normal vim commands (:new filename
), or do anything you want with the filename.
I made a little helper function so you can have it open in a new split, vsplit, or current window.
local function switch_source_header_splitcmd(bufnr, splitcmd)
bufnr = require'lspconfig'.util.validate_bufnr(bufnr)
local params = { uri = vim.uri_from_bufnr(bufnr) }
vim.lsp.buf_request(bufnr, 'textDocument/switchSourceHeader', params, function(err, _, result)
if err then error(tostring(err)) end
if not result then print ("Corresponding file can’t be determined") return end
vim.api.nvim_command(splitcmd..' '..vim.uri_to_fname(result))
end)
end
require'lspconfig'.clangd.switch_source_header_splitcmd = switch_source_header_splitcmd
require'lspconfig'.clangd.setup {
-----snip------
commands = {
ClangdSwitchSourceHeader = {
function() switch_source_header_splitcmd(0, "edit") end;
description = "Open source/header in a new vsplit";
},
ClangdSwitchSourceHeaderVSplit = {
function() switch_source_header_splitcmd(0, "vsplit") end;
description = "Open source/header in a new vsplit";
},
ClangdSwitchSourceHeaderSplit = {
function() switch_source_header_splitcmd(0, "split") end;
description = "Open source/header in a new split";
}
}
}
Then you can call the commands like ordinary vim commands, e.g.
:ClangdSwitchSourceHeaderVSplit
or
nnoremap <leader>h :ClangdSwitchSourceHeader<CR>