feat(lsp,debugger,formatting): C/C++ setup with clang
This commit is contained in:
27
lua/dap-lldb/COPYRIGHT
Normal file
27
lua/dap-lldb/COPYRIGHT
Normal file
@@ -0,0 +1,27 @@
|
||||
Contents of `dap-lldb/init.lua` were copied from julianolf's
|
||||
nvim-dap-lldb plugin at Git commit `0bf5fcd01a160fd918831591e715e2bd1e01073e` <https://github.com/julianolf/nvim-dap-lldb/tree/0bf5fcd01a160fd918831591e715e2bd1e01073e>,
|
||||
which is licensed under the MIT License. A copy of the original license can be found at
|
||||
the nvim-dap-go's GitHub repositoy <https://github.com/julianolf/nvim-dap-lldb/blob/b4421153ead5d726603b02743ea40cf26a51ed5f/LICENSE>
|
||||
and below:
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2024 Juliano Fernandes
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
238
lua/dap-lldb/init.lua
Normal file
238
lua/dap-lldb/init.lua
Normal file
@@ -0,0 +1,238 @@
|
||||
---@mod dap-lldb LLDB extension for nvim-dap
|
||||
|
||||
---@brief [[
|
||||
---An extension for nvim-dap to provide C, C++, and Rust debugging support.
|
||||
---@brief ]]
|
||||
|
||||
local M = {}
|
||||
|
||||
local ts_query = [[
|
||||
(mod_item
|
||||
name: (identifier) @module
|
||||
body: (declaration_list
|
||||
(attribute_item (attribute (identifier) @attribute (#eq? @attribute "test")))
|
||||
(function_item
|
||||
name: (identifier) @function)))
|
||||
]]
|
||||
|
||||
local function require_dap()
|
||||
local ok, dap = pcall(require, "dap")
|
||||
assert(ok, "nvim-dap is required to use dap-lldb")
|
||||
return dap
|
||||
end
|
||||
|
||||
local function compiler_error(input)
|
||||
local _, json = pcall(vim.fn.json_decode, input)
|
||||
|
||||
if type(json) == "table" and json.reason == "compiler-message" then
|
||||
return json.message.rendered
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function compiler_target(input)
|
||||
local _, json = pcall(vim.fn.json_decode, input)
|
||||
|
||||
if
|
||||
type(json) == "table"
|
||||
and json.reason == "compiler-artifact"
|
||||
and json.executable ~= nil
|
||||
and (vim.tbl_contains(json.target.kind, "bin") or json.profile.test)
|
||||
then
|
||||
return json.executable
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function read_target()
|
||||
local cwd = vim.fs.joinpath(vim.fn.getcwd(), "")
|
||||
return vim.fn.input("Path to executable: ", cwd, "file")
|
||||
end
|
||||
|
||||
local function list_targets(selection)
|
||||
local arg = string.format("--%s", selection or "bins")
|
||||
local cmd = { "cargo", "build", arg, "--quiet", "--message-format", "json" }
|
||||
local out = vim.fn.systemlist(cmd)
|
||||
|
||||
if vim.v.shell_error ~= 0 then
|
||||
local errors = vim.tbl_map(compiler_error, out)
|
||||
vim.notify(table.concat(errors, "\n"), vim.log.levels.ERROR)
|
||||
return nil
|
||||
end
|
||||
|
||||
local function filter(e)
|
||||
return e ~= nil
|
||||
end
|
||||
|
||||
return vim.tbl_filter(filter, vim.tbl_map(compiler_target, out))
|
||||
end
|
||||
|
||||
local function select_target(selection)
|
||||
local targets = list_targets(selection)
|
||||
|
||||
if targets == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
if #targets == 0 then
|
||||
return read_target()
|
||||
end
|
||||
|
||||
if #targets == 1 then
|
||||
return targets[1]
|
||||
end
|
||||
|
||||
local options = { "Select a target:" }
|
||||
|
||||
for index, target in ipairs(targets) do
|
||||
local name = vim.fs.basename(target)
|
||||
local option = string.format("%d. %s", index, name)
|
||||
table.insert(options, option)
|
||||
end
|
||||
|
||||
local choice = vim.fn.inputlist(options)
|
||||
|
||||
return targets[choice]
|
||||
end
|
||||
|
||||
local function select_test()
|
||||
local filetype = vim.bo.filetype
|
||||
|
||||
if filetype ~= "rust" or vim.treesitter.language.get_lang(filetype) == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local query = vim.treesitter.query.parse(filetype, ts_query)
|
||||
local parser = vim.treesitter.get_parser(bufnr, filetype)
|
||||
local tree = parser:parse()[1]
|
||||
local root = tree:root()
|
||||
local stop = vim.api.nvim_win_get_cursor(0)[1]
|
||||
local mod = nil
|
||||
local fun = nil
|
||||
|
||||
for id, node in query:iter_captures(root, bufnr, 0, stop) do
|
||||
local capture = query.captures[id]
|
||||
|
||||
if capture == "module" then
|
||||
mod = vim.treesitter.get_node_text(node, 0)
|
||||
elseif capture == "function" then
|
||||
fun = vim.treesitter.get_node_text(node, 0)
|
||||
end
|
||||
end
|
||||
|
||||
if not mod or not fun then
|
||||
return nil
|
||||
end
|
||||
|
||||
return string.format("%s::%s", mod, fun)
|
||||
end
|
||||
|
||||
local function read_args()
|
||||
local args = vim.fn.input("Enter args: ")
|
||||
return vim.split(args, " ", { trimempty = true })
|
||||
end
|
||||
|
||||
local function default_configurations(dap)
|
||||
local cfg = {
|
||||
name = "Debug",
|
||||
type = "lldb",
|
||||
request = "launch",
|
||||
cwd = "${workspaceFolder}",
|
||||
program = read_target,
|
||||
stopOnEntry = false,
|
||||
}
|
||||
|
||||
dap.configurations.c = {
|
||||
cfg,
|
||||
vim.tbl_extend("force", cfg, { name = "Debug (+args)", args = read_args }),
|
||||
vim.tbl_extend("force", cfg, { name = "Attach debugger", request = "attach" }),
|
||||
}
|
||||
|
||||
dap.configurations.cpp = vim.tbl_extend("keep", {}, dap.configurations.c)
|
||||
|
||||
dap.configurations.rust = {
|
||||
vim.tbl_extend("force", cfg, { program = select_target }),
|
||||
vim.tbl_extend("force", cfg, { name = "Debug (+args)", program = select_target, args = read_args }),
|
||||
vim.tbl_extend("force", cfg, {
|
||||
name = "Debug tests",
|
||||
program = function()
|
||||
return select_target("tests")
|
||||
end,
|
||||
args = { "--test-threads=1" },
|
||||
}),
|
||||
vim.tbl_extend("force", cfg, {
|
||||
name = "Debug tests (+args)",
|
||||
program = function()
|
||||
return select_target("tests")
|
||||
end,
|
||||
args = function()
|
||||
return vim.list_extend(read_args(), { "--test-threads=1" })
|
||||
end,
|
||||
}),
|
||||
vim.tbl_extend("force", cfg, {
|
||||
name = "Debug test (cursor)",
|
||||
program = function()
|
||||
return select_target("tests")
|
||||
end,
|
||||
args = function()
|
||||
local test = select_test()
|
||||
local args = test and { "--exact", test } or {}
|
||||
return vim.list_extend(args, { "--test-threads=1" })
|
||||
end,
|
||||
}),
|
||||
vim.tbl_extend("force", cfg, { name = "Attach debugger", request = "attach", program = select_target }),
|
||||
}
|
||||
end
|
||||
|
||||
local function custom_configurations(dap, opts)
|
||||
if type(opts.configurations) == "table" then
|
||||
for lang, cfg in pairs(opts.configurations) do
|
||||
local config = dap.configurations[lang] or {}
|
||||
dap.configurations[lang] = vim.list_extend(config, cfg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@class SetupOpts
|
||||
---@field codelldb_path string|nil Path to CodeLLDB extension
|
||||
---@field configurations table|nil Per programming language configuration
|
||||
---@see https://github.com/vadimcn/codelldb/blob/master/MANUAL.md
|
||||
|
||||
---Register LLDB debug adapter
|
||||
---@param opts SetupOpts|nil See |dap-lldb.SetupOpts|
|
||||
function M.setup(opts)
|
||||
opts = type(opts) == "table" and opts or {}
|
||||
|
||||
local dap = require_dap()
|
||||
local codelldb = opts.codelldb_path or "codelldb"
|
||||
|
||||
dap.adapters.lldb = {
|
||||
type = "server",
|
||||
port = "${port}",
|
||||
executable = {
|
||||
command = codelldb,
|
||||
args = { "--port", "${port}" },
|
||||
detached = vim.loop.os_uname().sysname ~= "Windows",
|
||||
},
|
||||
}
|
||||
|
||||
default_configurations(dap)
|
||||
custom_configurations(dap, opts)
|
||||
end
|
||||
|
||||
---Debug test function above the cursor
|
||||
function M.debug_test()
|
||||
if vim.bo.filetype ~= "rust" then
|
||||
vim.notify("This feature is available only for Rust", vim.log.levels.ERROR)
|
||||
return nil
|
||||
end
|
||||
|
||||
local dap = require_dap()
|
||||
local cfg = dap.configurations.rust[5]
|
||||
dap.run(cfg)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -18,5 +18,8 @@ end
|
||||
|
||||
-- Languages
|
||||
|
||||
-- C/C++
|
||||
require("dap-lldb").setup()
|
||||
|
||||
-- Go
|
||||
require("dap-go").setup()
|
||||
|
||||
@@ -24,6 +24,8 @@ end
|
||||
|
||||
conform.setup({
|
||||
formatters_by_ft = {
|
||||
c = { "clang-format", lsp_format = "fallback" },
|
||||
cpp = { "clang-format", lsp_format = "fallback" },
|
||||
css = prettier,
|
||||
gdscript = { "gdformat" },
|
||||
go = function(bufnr)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
---@type lze.PluginSpec[] | { lsp: vim.lsp.Config }[]
|
||||
return {
|
||||
-- Language Server Providers
|
||||
{
|
||||
"clangd",
|
||||
lsp = { filetypes = { "c", "cpp", "objc", "objcpp", "cuda" } },
|
||||
},
|
||||
{
|
||||
"cssls",
|
||||
lsp = { filetypes = { "css", "scss", "less" } },
|
||||
|
||||
@@ -109,6 +109,7 @@ in
|
||||
|
||||
vscode-langservers-extracted # cssls, eslint, html, jsonls, typescript
|
||||
|
||||
clang-tools
|
||||
docker-language-server
|
||||
emmet-language-server
|
||||
golangci-lint-langserver
|
||||
|
||||
Reference in New Issue
Block a user