Some checks are pending
Check Lua Formatting in MyRepo / Stylua Check (push) Waiting to run
196 lines
5.6 KiB
Lua
196 lines
5.6 KiB
Lua
-- Indentation settings
|
|
vim.bo.expandtab = true -- Use spaces instead of tabs
|
|
vim.bo.tabstop = 4 -- Number of spaces per tab
|
|
vim.bo.shiftwidth = 4 -- Number of spaces for autoindent
|
|
vim.bo.softtabstop = 4 -- Number of spaces for editing
|
|
vim.bo.formatoptions = vim.bo.formatoptions:gsub('o', '') -- Remove 'o'
|
|
|
|
-- Format on save using Conform
|
|
local augroup = vim.api.nvim_create_augroup('CFormat', { clear = true })
|
|
vim.api.nvim_create_autocmd('BufWritePre', {
|
|
group = augroup,
|
|
pattern = '*.c',
|
|
callback = function()
|
|
if vim.fn.exists(':ConformFormat') == 2 then
|
|
vim.cmd('ConformFormat')
|
|
end
|
|
end,
|
|
})
|
|
|
|
local function cmake_build_dir(name)
|
|
local dir = vim.fn.getcwd() .. '/' .. (name or 'build')
|
|
if vim.fn.isdirectory(dir) == 0 then
|
|
vim.fn.mkdir(dir, 'p')
|
|
end
|
|
return dir
|
|
end
|
|
|
|
local function cmake_configure(build_dir, extra_args)
|
|
local args = extra_args or ''
|
|
local bin_dir = vim.fn.getcwd() .. '/bin'
|
|
vim.fn.mkdir(bin_dir, 'p')
|
|
local out_args =
|
|
' -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=' .. vim.fn.shellescape(bin_dir) .. ' -DCMAKE_LIBRARY_OUTPUT_DIRECTORY='
|
|
.. vim.fn.shellescape(bin_dir)
|
|
.. ' -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY='
|
|
.. vim.fn.shellescape(bin_dir)
|
|
vim.cmd('!cmake -S . -B ' .. vim.fn.fnameescape(build_dir) .. out_args .. ' ' .. args)
|
|
end
|
|
|
|
local function cmake_build(build_dir)
|
|
vim.cmd('!cmake --build ' .. vim.fn.fnameescape(build_dir))
|
|
end
|
|
|
|
local function cmake_ctest(build_dir)
|
|
vim.cmd('!ctest --test-dir ' .. vim.fn.fnameescape(build_dir) .. ' --output-on-failure')
|
|
end
|
|
|
|
local function toggle_debugger_repl()
|
|
local dbg = vim.__c_dbg_term
|
|
if dbg and dbg.is_open and dbg:is_open() then
|
|
dbg:close()
|
|
return
|
|
end
|
|
|
|
local ok_term, term_mod = pcall(require, 'toggleterm.terminal')
|
|
if not ok_term then
|
|
return
|
|
end
|
|
|
|
local cmd
|
|
if vim.fn.has('mac') == 1 then
|
|
cmd = 'lldb'
|
|
else
|
|
cmd = 'gdb'
|
|
end
|
|
|
|
if not vim.__c_dbg_term then
|
|
vim.__c_dbg_term = term_mod.Terminal:new({
|
|
cmd = cmd,
|
|
direction = 'vertical',
|
|
size = function()
|
|
return math.floor(vim.o.columns * 0.4)
|
|
end,
|
|
hidden = true,
|
|
on_open = function(term)
|
|
vim.api.nvim_buf_set_keymap(term.bufnr, 'n', 'q', '<cmd>close<CR>', { noremap = true, silent = true })
|
|
vim.api.nvim_buf_set_keymap(term.bufnr, 't', '<Esc><Esc>', '<C-\\><C-n>', { noremap = true, silent = true })
|
|
end,
|
|
})
|
|
end
|
|
|
|
vim.__c_dbg_term:open()
|
|
vim.cmd('wincmd p')
|
|
end
|
|
|
|
local opts = { buffer = true, silent = true }
|
|
|
|
local function switch_source_header()
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
local function edit_file(fname)
|
|
if not fname or fname == '' then
|
|
return
|
|
end
|
|
vim.cmd('edit ' .. vim.fn.fnameescape(fname))
|
|
end
|
|
|
|
local clangd
|
|
for _, client in ipairs(vim.lsp.get_clients({ bufnr = bufnr })) do
|
|
if client.name == 'clangd' then
|
|
clangd = client
|
|
break
|
|
end
|
|
end
|
|
|
|
if clangd then
|
|
clangd.request('textDocument/switchSourceHeader', { uri = vim.uri_from_bufnr(bufnr) }, function(err, result)
|
|
if err then
|
|
vim.notify('clangd: switchSourceHeader failed', vim.log.levels.WARN)
|
|
return
|
|
end
|
|
if not result then
|
|
vim.notify('No corresponding header/source found', vim.log.levels.INFO)
|
|
return
|
|
end
|
|
vim.schedule(function()
|
|
edit_file(vim.uri_to_fname(result))
|
|
end)
|
|
end, bufnr)
|
|
return
|
|
end
|
|
|
|
local file = vim.api.nvim_buf_get_name(bufnr)
|
|
if file == '' then
|
|
return
|
|
end
|
|
|
|
local root = file:gsub('%.[^%.]+$', '')
|
|
local ext = vim.fn.fnamemodify(file, ':e')
|
|
local candidates
|
|
|
|
if ext == 'h' or ext == 'hpp' or ext == 'hh' or ext == 'hxx' then
|
|
candidates = { 'c', 'cpp', 'cc', 'cxx' }
|
|
elseif ext == 'c' then
|
|
candidates = { 'h' }
|
|
else
|
|
candidates = { 'h', 'hpp', 'hh', 'hxx' }
|
|
end
|
|
|
|
for _, e in ipairs(candidates) do
|
|
local cand = root .. '.' .. e
|
|
if vim.fn.filereadable(cand) == 1 then
|
|
edit_file(cand)
|
|
return
|
|
end
|
|
end
|
|
|
|
vim.notify('No corresponding header/source found', vim.log.levels.INFO)
|
|
end
|
|
|
|
local function memory_profile_command(run_cmd)
|
|
if vim.fn.has('mac') == 1 then
|
|
return 'leaks --atExit -- ' .. run_cmd
|
|
end
|
|
return 'valgrind --leak-check=full --track-origins=yes ' .. run_cmd
|
|
end
|
|
|
|
vim.keymap.set('n', '<leader>cb', function()
|
|
local build_dir = cmake_build_dir('build')
|
|
cmake_configure(build_dir)
|
|
cmake_build(build_dir)
|
|
end, vim.tbl_extend('force', opts, { desc = 'CMake: Build' }))
|
|
|
|
vim.keymap.set('n', '<leader>ct', function()
|
|
local build_dir = cmake_build_dir('build')
|
|
cmake_ctest(build_dir)
|
|
end, vim.tbl_extend('force', opts, { desc = 'CMake: Test' }))
|
|
|
|
vim.keymap.set('n', '<leader>ch', switch_source_header, vim.tbl_extend('force', opts, { desc = 'C: Switch header/source' }))
|
|
|
|
vim.keymap.set('n', '<leader>cg', toggle_debugger_repl, vim.tbl_extend('force', opts, { desc = 'C: Toggle debugger REPL' }))
|
|
|
|
vim.keymap.set('n', '<leader>cm', function()
|
|
local cmd = vim.fn.input('Memory profile run: ', './bin/')
|
|
if cmd == '' then
|
|
return
|
|
end
|
|
vim.cmd('!' .. memory_profile_command(cmd))
|
|
end, vim.tbl_extend('force', opts, { desc = 'C: Memory profile (leaks/valgrind)' }))
|
|
|
|
vim.keymap.set('n', '<leader>Rr', toggle_debugger_repl, vim.tbl_extend('force', opts, { desc = 'Run/REPL: Toggle' }))
|
|
|
|
vim.keymap.set('n', '<leader>Rf', function()
|
|
local cmd = vim.fn.input('Run: ', './bin/')
|
|
if cmd == '' then
|
|
return
|
|
end
|
|
vim.cmd('!' .. cmd)
|
|
end, vim.tbl_extend('force', opts, { desc = 'Run/REPL: Run' }))
|
|
|
|
vim.keymap.set('n', '<leader>Ri', function()
|
|
local dbg = vim.__c_dbg_term
|
|
if dbg and dbg.send and dbg.is_open and dbg:is_open() then
|
|
dbg:send('\x03')
|
|
end
|
|
end, vim.tbl_extend('force', opts, { desc = 'Run/REPL: Interrupt' }))
|
|
|