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 # 2025-02-07
scrollOff = "scrolloff"; scrollOff = "scrolloff";
}; };
lspOptRemovalMsg = ''
`vim.languages.<lang>.lsp.opts` are now moved to `vim.lsp.servers.<server_name>.init_options`
'';
in { in {
imports = concatLists [ imports = concatLists [
[ [
@ -111,6 +115,9 @@ in {
under the diagnostics module. Please consider using one of 'vim.diagnostics.config' or 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. '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. # Migrated via batchRenameOptions. Further batch renames must be below this line.

View file

@ -5,47 +5,168 @@
... ...
}: let }: let
inherit (builtins) attrNames; inherit (builtins) attrNames;
inherit (lib.lists) isList;
inherit (lib.strings) optionalString;
inherit (lib.options) mkEnableOption mkOption; 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.modules) mkIf mkMerge;
inherit (lib.nvim.lua) expToLua; inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.types) mkGrammarOption; inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.dag) entryAfter; 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; cfg = config.vim.languages.clang;
defaultServer = "clangd"; defaultServer = ["clangd"];
servers = { servers = {
ccls = { ccls.options = {
package = pkgs.ccls; cmd = [(getExe pkgs.ccls)];
lspConfig = '' filetypes = ["c" "cpp" "objc" "objcpp" "cuda"];
lspconfig.ccls.setup{ offset_encoding = "utf-32";
capabilities = capabilities; root_dir = mkLuaInline ''
on_attach=default_on_attach; function(bufnr, cb)
cmd = ${packageToCmd cfg.lsp.package "ccls"}; local dir = vim.fs.root(bufnr, {"compile_commands.json", ".ccls"})
${optionalString (cfg.lsp.opts != null) "init_options = ${cfg.lsp.opts}"} 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; clangd.options = {
lspConfig = '' cmd = ["${pkgs.clang-tools}/bin/clangd"];
local clangd_cap = capabilities filetypes = ["c" "cpp" "objc" "objcpp" "cuda" "proto"];
-- use same offsetEncoding as null-ls root_dir = mkLuaInline ''
clangd_cap.offsetEncoding = {"utf-16"} function(bufnr, cb)
lspconfig.clangd.setup{ local dir = vim.fs.root(bufnr, {
capabilities = clangd_cap; '.clangd',
on_attach=default_on_attach; '.clang-tidy',
cmd = ${packageToCmd cfg.lsp.package "clangd"}; '.clang-format',
${optionalString (cfg.lsp.opts != null) "init_options = ${cfg.lsp.opts}"} '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 { server = mkOption {
description = "The clang LSP server to use"; description = "The clang LSP server to use";
type = enum (attrNames servers); type = listOf (enum (attrNames servers));
default = defaultServer; 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 = { dap = {
@ -150,9 +258,12 @@ in {
}) })
(mkIf cfg.lsp.enable { (mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true; vim.lsp.servers =
mapListToAttrs (name: {
vim.lsp.lspconfig.sources.clang-lsp = servers.${cfg.lsp.server}.lspConfig; inherit name;
value = servers.${name}.options;
})
cfg.lsp.server;
}) })
(mkIf cfg.dap.enable { (mkIf cfg.dap.enable {