diff --git a/lua/plugins/config/compile-commands-picker.lua b/lua/plugins/config/compile-commands-picker.lua new file mode 100644 index 00000000..bc7c5c86 --- /dev/null +++ b/lua/plugins/config/compile-commands-picker.lua @@ -0,0 +1,137 @@ +-- 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') + + pickers.new({}, { + prompt_title = 'Select compile_commands.json', + finder = finders.new_table { + results = files, + entry_maker = function(entry) + return { + value = entry, + display = entry.display, + ordinal = entry.display, + } + end, + }, + sorter = conf.generic_sorter{}, + 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_active_clients({ name = 'clangd' }) + if #clients > 0 then + vim.notify('Restarting clangd...', vim.log.levels.INFO) + vim.cmd('LspRestart clangd') + 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 \ No newline at end of file diff --git a/lua/plugins/config/lsp/init.lua b/lua/plugins/config/lsp/init.lua index 930dd4a4..fab3e1d8 100644 --- a/lua/plugins/config/lsp/init.lua +++ b/lua/plugins/config/lsp/init.lua @@ -21,6 +21,9 @@ function M.setup() -- Setup LSP keymaps require('plugins.config.lsp.keymaps').setup() + + -- Setup compile_commands.json picker for C/C++ projects + require('plugins.config.compile-commands-picker').setup() end return M \ No newline at end of file diff --git a/lua/plugins/config/lsp/servers.lua b/lua/plugins/config/lsp/servers.lua index 3f761eb5..f416dc02 100644 --- a/lua/plugins/config/lsp/servers.lua +++ b/lua/plugins/config/lsp/servers.lua @@ -9,7 +9,7 @@ local function get_clangd_query_driver() '/nix/store/*/bin/clang*', '/opt/homebrew/opt/llvm/bin/clang*', '/usr/bin/clang*', - }, ';') + }, ':') end -- Get clang resource directory diff --git a/lua/plugins/config/telescope.lua b/lua/plugins/config/telescope.lua index 119919b0..60275b80 100644 --- a/lua/plugins/config/telescope.lua +++ b/lua/plugins/config/telescope.lua @@ -79,6 +79,10 @@ function M.setup() vim.keymap.set('n', 'sn', function() builtin.find_files { cwd = vim.fn.stdpath 'config' } end, { desc = '[S]earch [N]eovim files' }) + + -- C/C++ compile_commands.json picker + vim.keymap.set('n', 'sc', 'CompileCommandsPicker', + { desc = '[S]earch [C]ompile commands.json' }) end return M \ No newline at end of file