language/clang: migrate to vim.lsp.servers

This commit is contained in:
Ching Pei Yang 2025-04-06 00:39:14 +02:00
parent 583f436e6e
commit e621af1410
No known key found for this signature in database
GPG key ID: B3841364253DC4C8
2 changed files with 166 additions and 48 deletions

View file

@ -20,6 +20,10 @@
# 2025-02-07
scrollOff = "scrolloff";
};
lspOptRemovalMsg = ''
`vim.languages.<lang>.lsp.opts` are now moved to `vim.lsp.servers.<server_name>.init_options`
'';
in {
imports = concatLists [
[
@ -111,6 +115,9 @@ in {
under the diagnostics module. Please consider using one of 'vim.diagnostics.config' or
'vim.luaConfigRC' to configure LSP lines for Neovim through its own diagnostics API.
'')
# 2025-04-05
(mkRemovedOptionModule ["vim" "languages" "clang" "lsp" "opts"] lspOptRemovalMsg)
]
# Migrated via batchRenameOptions. Further batch renames must be below this line.

View file

@ -5,47 +5,168 @@
...
}: let
inherit (builtins) attrNames;
inherit (lib.lists) isList;
inherit (lib.strings) optionalString;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.types) bool enum package either listOf str nullOr;
inherit (lib.types) bool enum package listOf;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.nvim.lua) expToLua;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.dag) entryAfter;
packageToCmd = package: defaultCmd:
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{ "${cfg.lsp.package}/bin/${defaultCmd}" }'';
cfg = config.vim.languages.clang;
defaultServer = "clangd";
defaultServer = ["clangd"];
servers = {
ccls = {
package = pkgs.ccls;
lspConfig = ''
lspconfig.ccls.setup{
capabilities = capabilities;
on_attach=default_on_attach;
cmd = ${packageToCmd cfg.lsp.package "ccls"};
${optionalString (cfg.lsp.opts != null) "init_options = ${cfg.lsp.opts}"}
}
ccls.options = {
cmd = [(getExe pkgs.ccls)];
filetypes = ["c" "cpp" "objc" "objcpp" "cuda"];
offset_encoding = "utf-32";
root_dir = mkLuaInline ''
function(bufnr, cb)
local dir = vim.fs.root(bufnr, {"compile_commands.json", ".ccls"})
or vim.fs.root(bufnr, {".git"})
if dir then cb(dir) end
end
'';
on_attach = mkLuaInline ''
function(client, bufnr)
default_on_attach(client, bufnr)
local function switch_source_header(bufnr)
local method_name = "textDocument/switchSourceHeader"
local client = vim.lsp.get_clients({
bufnr = bufnr,
name = "ccls",
method = method_name,
})[1]
if not client then
return vim.notify(('method %s is not supported by any servers active on the current buffer'):format(method_name))
end
local params = vim.lsp.util.make_text_document_params(bufnr)
client:request(method_name, params, function(err, result)
if err then
error(tostring(err))
end
if not result then
vim.notify('corresponding file cannot be determined')
return
end
vim.cmd.edit(vim.uri_to_fname(result))
end, bufnr)
end
vim.api.nvim_buf_create_user_command(
bufnr,
"CclsSwitchSourceHeader",
function(arg)
switch_source_header(0)
end,
{desc = "Switch between source/header"}
)
end
'';
};
clangd = {
package = pkgs.clang-tools;
lspConfig = ''
local clangd_cap = capabilities
-- use same offsetEncoding as null-ls
clangd_cap.offsetEncoding = {"utf-16"}
lspconfig.clangd.setup{
capabilities = clangd_cap;
on_attach=default_on_attach;
cmd = ${packageToCmd cfg.lsp.package "clangd"};
${optionalString (cfg.lsp.opts != null) "init_options = ${cfg.lsp.opts}"}
}
clangd.options = {
cmd = ["${pkgs.clang-tools}/bin/clangd"];
filetypes = ["c" "cpp" "objc" "objcpp" "cuda" "proto"];
root_dir = mkLuaInline ''
function(bufnr, cb)
local dir = vim.fs.root(bufnr, {
'.clangd',
'.clang-tidy',
'.clang-format',
'compile_commands.json',
'compile_flags.txt',
'configure.ac' -- AutoTools
}) or vim.fs.root(bufnr, {".git"})
if dir then cb(dir) end
end
'';
capabilities = {
textDocument = {
completion = {
editsNearCursor = true;
};
};
offsetEncoding = ["utf-8" "utf-16"];
};
on_attach = mkLuaInline ''
function(client, bufnr)
default_on_attach(client, bufnr)
local function switch_source_header(bufnr)
local method_name = "textDocument/switchSourceHeader"
local client = vim.lsp.get_clients({
bufnr = bufnr,
name = "clangd",
method = method_name,
})[1]
if not client then
return vim.notify(('method %s is not supported by any servers active on the current buffer'):format(method_name))
end
local params = vim.lsp.util.make_text_document_params(bufnr)
client:request(method_name, params, function(err, result)
if err then
error(tostring(err))
end
if not result then
vim.notify('corresponding file cannot be determined')
return
end
vim.cmd.edit(vim.uri_to_fname(result))
end, bufnr)
end
local function symbol_info()
local clangd_client = vim.lsp.get_clients({
bufnr = 0,
name = "clangd",
method = "textDocument/symbolInfo",
})[1]
if not clangd_client or not clangd_client.supports_method 'textDocument/symbolInfo' then
return vim.notify('Clangd client not found', vim.log.levels.ERROR)
end
local win = vim.api.nvim_get_current_win()
local params = vim.lsp.util.make_position_params(win, clangd_client.offset_encoding)
clangd_client:request('textDocument/symbolInfo', params, function(err, res)
if err or #res == 0 then
-- Clangd always returns an error, there is not reason to parse it
return
end
local container = string.format('container: %s', res[1].containerName) ---@type string
local name = string.format('name: %s', res[1].name) ---@type string
vim.lsp.util.open_floating_preview({ name, container }, "", {
height = 2,
width = math.max(string.len(name), string.len(container)),
focusable = false,
focus = false,
border = 'single',
title = 'Symbol Info',
})
end, bufnr)
end
vim.api.nvim_buf_create_user_command(
bufnr,
"ClangdSwitchSourceHeader",
function(arg)
switch_source_header(0)
end,
{desc = "Switch between source/header"}
)
vim.api.nvim_buf_create_user_command(
bufnr,
"ClangdShowSymbolInfo",
function(arg)
symbol_info()
end,
{desc = "Show symbol info"}
)
end
'';
};
};
@ -102,22 +223,9 @@ in {
server = mkOption {
description = "The clang LSP server to use";
type = enum (attrNames servers);
type = listOf (enum (attrNames servers));
default = defaultServer;
};
package = mkOption {
description = "clang LSP server package, or the command to run as a list of strings";
example = ''[lib.getExe pkgs.jdt-language-server " - data " " ~/.cache/jdtls/workspace "]'';
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
};
opts = mkOption {
description = "Options to pass to clang LSP server";
type = nullOr str;
default = null;
};
};
dap = {
@ -150,9 +258,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.clang-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (name: {
inherit name;
value = servers.${name}.options;
})
cfg.lsp.server;
})
(mkIf cfg.dap.enable {