-- Explicit test loading leaves Neovim's persistent exrc trust database unchanged. if vim.env.MODULUS_NVIM_USER_CONFIG == "1" then dofile(vim.fn.stdpath("config") .. "/init.lua") require("lazy").load({ plugins = { "nvim-lspconfig" } }) else vim.lsp.config("clangd", { cmd = { "clangd" }, filetypes = { "c", "cpp" }, capabilities = { offsetEncoding = { "utf-16" } } }) end vim.o.exrc = false local root = assert(vim.env.MODULUS_LSP_REPO) local attached = false local previous = vim.lsp.config.clangd.on_attach local on_attach = function(client, buffer) attached = true if previous then previous(client, buffer) end end vim.lsp.config("clangd", { on_attach = on_attach, capabilities = { modulus_test = true } }) local original_cmd = vim.lsp.config.clangd.cmd dofile(root .. "/.nvim.lua") assert(vim.lsp.config.clangd.on_attach == on_attach) assert(vim.lsp.config.clangd.capabilities.modulus_test) local rpc_start = vim.lsp.rpc.start local fallback vim.lsp.rpc.start = function(command) fallback = command end vim.lsp.config.clangd.cmd({}, { root_dir = "/tmp/not-a-modulus-project" }) vim.lsp.rpc.start = rpc_start assert(vim.deep_equal(fallback, original_cmd), "non-Modulus server command changed") vim.schedule(function() local ok, error = pcall(function() vim.cmd.edit(root .. "/" .. assert(vim.env.MODULUS_LSP_SOURCE)) assert(vim.wait(60000, function() local clients = vim.lsp.get_clients({ bufnr = 0, name = "clangd" }) return #clients == 1 and clients[1].initialized and attached end, 50), "container clangd did not attach") local clients = vim.lsp.get_clients({ bufnr = 0, name = "clangd" }) assert(#clients == 1, "duplicate clangd clients") local client = clients[1] assert(client.config._modulus_container, "not the container server") assert(client.config.root_dir == root, "wrong root") local header = vim.env.MODULUS_LSP_HEADER or "cstdint" local changed = false local notification = vim.api.nvim_create_autocmd("LspNotify", { callback = function(event) if event.data.method == "textDocument/didChange" then changed = true end end, }) vim.api.nvim_buf_set_lines(0, 0, 0, false, { "#include <" .. header .. ">" }) assert(vim.wait(5000, function() return changed end, 10), "buffer change was not sent") vim.api.nvim_del_autocmd(notification) local result = assert(client:request_sync("textDocument/definition", { textDocument = { uri = vim.uri_from_bufnr(0) }, position = { line = 0, character = 12 }, }, 60000, 0)) assert(result.result and #result.result > 0, vim.inspect(result)) local errors = vim.diagnostic.get(0, { severity = vim.diagnostic.severity.ERROR }) assert(#errors == 0, vim.inspect(errors)) local location = result.result[1] local target = vim.uri_to_fname(location.uri or location.targetUri) assert(target:find("/modulus/clangd/", 1, true), target) vim.lsp.util.show_document(location, client.offset_encoding, { focus = true }) assert(vim.bo.readonly and not vim.bo.modifiable, "cached header is writable") assert(#vim.lsp.get_clients({ name = "clangd" }) == 1, "navigation spawned another clangd") print("MODULUS_NVIM_OK " .. root .. " " .. target) client:stop() vim.wait(20000, function() return client:is_stopped() end, 50) end) if not ok then print("MODULUS_NVIM_FAILURE " .. tostring(error)) vim.cmd("cquit 1") end vim.cmd("qa!") end)