language/clang: migrate to vim.lsp.servers

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

View file

@ -20,6 +20,10 @@
# 2025-02-07 # 2025-02-07
scrollOffset = "scrolloff"; scrollOffset = "scrolloff";
}; };
lspOptRemovalMsg = ''
`vim.languages.<lang>.lsp.opts` are now moved to `vim.lsp.servers.<server_name>.init_options`
'';
in { in {
imports = concatLists [ imports = concatLists [
[ [
@ -120,6 +124,9 @@ in {
in 'vim.clipboard.registers'. Please see the documentation for the new module for more in 'vim.clipboard.registers'. Please see the documentation for the new module for more
details, or open an issue if you are confused. details, or open an issue if you are confused.
'') '')
# 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,143 @@
... ...
}: 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"; defaultServers = ["clangd"];
servers = { servers = {
ccls = { ccls = {
package = pkgs.ccls; cmd = [(getExe pkgs.ccls)];
lspConfig = '' filetypes = ["c" "cpp" "objc" "objcpp" "cuda"];
lspconfig.ccls.setup{ offset_encoding = "utf-32";
capabilities = capabilities; root_markers = ["compile_commands.json" ".ccls" ".git"];
on_attach=default_on_attach; workspace_required = true;
cmd = ${packageToCmd cfg.lsp.package "ccls"}; on_attach = mkLuaInline ''
${optionalString (cfg.lsp.opts != null) "init_options = ${cfg.lsp.opts}"} function(client, bufnr)
} default_on_attach(client, bufnr)
local function switch_source_header(bufnr)
local method_name = "textDocument/switchSourceHeader"
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,
"LspCclsSwitchSourceHeader",
function(arg)
switch_source_header(client, 0)
end,
{desc = "Switch between source/header"}
)
end
''; '';
}; };
clangd = { clangd = {
package = pkgs.clang-tools; cmd = ["${pkgs.clang-tools}/bin/clangd"];
lspConfig = '' filetypes = ["c" "cpp" "objc" "objcpp" "cuda" "proto"];
local clangd_cap = capabilities root_markers = [
-- use same offsetEncoding as null-ls ".clangd"
clangd_cap.offsetEncoding = {"utf-16"} ".clang-tidy"
lspconfig.clangd.setup{ ".clang-format"
capabilities = clangd_cap; "compile_commands.json"
on_attach=default_on_attach; "compile_flags.txt"
cmd = ${packageToCmd cfg.lsp.package "clangd"}; "configure.ac"
${optionalString (cfg.lsp.opts != null) "init_options = ${cfg.lsp.opts}"} ".git"
} ];
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", })[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 bufnr = vim.api.nvim_get_current_buf()
local clangd_client = vim.lsp.get_clients({ bufnr = bufnr, name = "clangd" })[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
''; '';
}; };
}; };
@ -100,23 +196,10 @@ in {
lsp = { lsp = {
enable = mkEnableOption "clang LSP support" // {default = config.vim.lsp.enable;}; enable = mkEnableOption "clang LSP support" // {default = config.vim.lsp.enable;};
server = mkOption { servers = 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 = defaultServers;
};
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;
}; };
}; };
@ -150,9 +233,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};
})
cfg.lsp.servers;
}) })
(mkIf cfg.dap.enable { (mkIf cfg.dap.enable {