local M = {} -- Get current file context function M.get_file_context() return { filepath = vim.fn.expand('%:p'), filename = vim.fn.expand('%:t'), filetype = vim.bo.filetype, line_count = vim.api.nvim_buf_line_count(0) } end -- Detect and extract visual selection function M.get_selection_info(range_given, line1, line2) local selection = nil if range_given then -- Command called with range selection = { start_line = line1, end_line = line2, text = table.concat(vim.api.nvim_buf_get_lines(0, line1 - 1, line2, false), '\n') } elseif vim.fn.mode() == 'v' or vim.fn.mode() == 'V' then -- Visual mode selection local start_pos = vim.fn.getpos("'<") local end_pos = vim.fn.getpos("'>") selection = { start_line = start_pos[2], end_line = end_pos[2], text = table.concat(vim.api.nvim_buf_get_lines(0, start_pos[2] - 1, end_pos[2], false), '\n') } end return selection end -- Build prompt with context function M.build_prompt(user_input, file_context, selection, is_edit_mode, diagnostic_info) local prompt_parts = {} -- Diagnostic fix mode instruction if diagnostic_info then table.insert(prompt_parts, "DIAGNOSTIC FIX MODE: Use your Edit tool to fix the following diagnostic issues in the code. Make precise fixes to resolve the specific problems listed.") table.insert(prompt_parts, diagnostic_info) elseif is_edit_mode then -- Edit mode instruction table.insert(prompt_parts, "EDIT MODE: Return ONLY the modified code with no explanations, markdown formatting, or additional text. Any explanations should be included as code comments within the code itself. Do not surround the code with backticks.") end -- File context table.insert(prompt_parts, string.format("File: %s (%s)", file_context.filename, file_context.filetype)) -- Selection context if present if selection then table.insert(prompt_parts, string.format("Selected lines %d-%d:", selection.start_line, selection.end_line)) table.insert(prompt_parts, "```" .. file_context.filetype) table.insert(prompt_parts, selection.text) table.insert(prompt_parts, "```") end -- User request table.insert(prompt_parts, "Request: " .. user_input) return table.concat(prompt_parts, '\n\n') end -- Execute claude command function M.execute_claude(prompt, callback) -- Alternative 1: Use vim.system (Neovim 0.10+) - cleaner, no shell escaping needed vim.system({ 'claude', '-p', prompt }, { text = true }, function(result) vim.schedule(function() if result.code == 0 then if callback then callback(result.stdout) end else vim.notify("Claude error: " .. (result.stderr or "Unknown error"), vim.log.levels.ERROR) end end) end) end -- Execute claude command with tool permissions for diagnostic fixing function M.execute_claude_with_tools(prompt, callback) vim.system({ 'claude', '--allowedTools=Edit,Read', '-p', prompt }, { text = true }, function(result) vim.schedule(function() if result.code == 0 then if callback then callback(result.stdout) end else vim.notify("Claude error: " .. (result.stderr or "Unknown error"), vim.log.levels.ERROR) end end) end) end -- Replace selection with new content function M.replace_selection(selection, new_content) local lines = vim.split(new_content, '\n') vim.api.nvim_buf_set_lines(0, selection.start_line - 1, selection.end_line, false, lines) end -- Check if claude binary exists function M.claude_available() return vim.fn.executable('claude') == 1 end return M