kickstart.nvim/lua/plugins/config/compile-commands-picker.lua

155 lines
4.4 KiB
Lua

-- Telescope picker for selecting compile_commands.json
local M = {}
local function find_compile_commands()
local root = vim.fn.getcwd()
local cmd = string.format('find "%s" -name compile_commands.json -type f 2>/dev/null', root)
local handle = io.popen(cmd)
if not handle then
return {}
end
local result = handle:read('*a')
handle:close()
local files = {}
for line in result:gmatch('[^\n]+') do
-- Get relative path for display
local relative = line:gsub('^' .. vim.pesc(root) .. '/', '')
table.insert(files, {
path = line,
display = relative,
dir = vim.fn.fnamemodify(line, ':h'),
relative_dir = vim.fn.fnamemodify(relative, ':h'),
})
end
return files
end
function M.pick_compile_commands()
local files = find_compile_commands()
if #files == 0 then
vim.notify('No compile_commands.json files found', vim.log.levels.WARN)
return
elseif #files == 1 then
vim.notify('Using: ' .. files[1].display, vim.log.levels.INFO)
M.set_compile_commands(files[1])
return
end
-- Multiple files found, show picker
local pickers = require('telescope.pickers')
local finders = require('telescope.finders')
local conf = require('telescope.config').values
local actions = require('telescope.actions')
local action_state = require('telescope.actions.state')
-- Create a simple path array for the finder
local paths = {}
local path_to_info = {}
for _, file in ipairs(files) do
table.insert(paths, file.path)
path_to_info[file.path] = file
end
pickers.new({}, {
prompt_title = 'Select compile_commands.json',
finder = finders.new_table {
results = paths, -- Pass simple path strings
entry_maker = function(path)
local info = path_to_info[path]
return {
value = info,
display = info.display,
ordinal = info.display,
path = path, -- This is what the previewer needs
}
end,
},
sorter = conf.generic_sorter{},
previewer = conf.file_previewer{},
attach_mappings = function(prompt_bufnr, map)
actions.select_default:replace(function()
actions.close(prompt_bufnr)
local selection = action_state.get_selected_entry()
if selection then
M.set_compile_commands(selection.value)
end
end)
return true
end,
}):find()
end
function M.set_compile_commands(file_info)
local clangd_config = string.format([[
CompileFlags:
CompilationDatabase: %s
]], file_info.relative_dir)
-- Write .clangd file
local clangd_file = vim.fn.getcwd() .. '/.clangd'
local file = io.open(clangd_file, 'w')
if file then
file:write(clangd_config)
file:close()
vim.notify('Created .clangd pointing to: ' .. file_info.relative_dir, vim.log.levels.INFO)
-- Restart LSP if clangd is running
local clients = vim.lsp.get_clients({ name = 'clangd' })
if #clients > 0 then
vim.notify('Restarting clangd...', vim.log.levels.INFO)
-- Stop and start clangd to pick up new config
for _, client in ipairs(clients) do
client.stop()
end
vim.defer_fn(function()
vim.cmd('LspStart clangd')
vim.notify('Clangd restarted with new configuration', vim.log.levels.INFO)
end, 100)
end
else
vim.notify('Failed to create .clangd file', vim.log.levels.ERROR)
end
end
-- Auto-detect multiple compile_commands.json on startup
function M.auto_detect()
local files = find_compile_commands()
if #files > 1 then
-- Check if .clangd already exists
local clangd_file = vim.fn.getcwd() .. '/.clangd'
if vim.fn.filereadable(clangd_file) == 0 then
vim.notify(
string.format('Found %d compile_commands.json files. Use :CompileCommandsPicker to select one.', #files),
vim.log.levels.INFO
)
end
end
end
-- Setup function to create command
function M.setup()
vim.api.nvim_create_user_command('CompileCommandsPicker', function()
M.pick_compile_commands()
end, { desc = 'Select compile_commands.json for clangd' })
-- Auto-detect on entering a C/C++ file
vim.api.nvim_create_autocmd('FileType', {
pattern = { 'c', 'cpp', 'objc', 'objcpp' },
callback = function()
-- Only run once per session
if not vim.g.compile_commands_detected then
vim.g.compile_commands_detected = true
vim.defer_fn(function()
M.auto_detect()
end, 100)
end
end,
})
end
return M