···11-local M = {}
22-33--- Get current file context
44-function M.get_file_context()
55- return {
66- filepath = vim.fn.expand('%:p'),
77- filename = vim.fn.expand('%:t'),
88- filetype = vim.bo.filetype,
99- line_count = vim.api.nvim_buf_line_count(0)
1010- }
1111-end
1212-1313--- Detect and extract visual selection
1414-function M.get_selection_info(range_given, line1, line2)
1515- local selection = nil
1616- if range_given then
1717- -- Command called with range
1818- selection = {
1919- start_line = line1,
2020- end_line = line2,
2121- text = table.concat(vim.api.nvim_buf_get_lines(0, line1 - 1, line2, false), '\n')
2222- }
2323- elseif vim.fn.mode() == 'v' or vim.fn.mode() == 'V' then
2424- -- Visual mode selection
2525- local start_pos = vim.fn.getpos("'<")
2626- local end_pos = vim.fn.getpos("'>")
2727- selection = {
2828- start_line = start_pos[2],
2929- end_line = end_pos[2],
3030- text = table.concat(vim.api.nvim_buf_get_lines(0, start_pos[2] - 1, end_pos[2], false), '\n')
3131- }
3232- end
3333- return selection
3434-end
3535-3636--- Build prompt with context
3737-function M.build_prompt(user_input, file_context, selection, is_edit_mode, diagnostic_info)
3838- local prompt_parts = {}
3939-4040- -- Diagnostic fix mode instruction
4141- if diagnostic_info then
4242- table.insert(prompt_parts,
4343- "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.")
4444- table.insert(prompt_parts, diagnostic_info)
4545- elseif is_edit_mode then
4646- -- Edit mode instruction
4747- table.insert(prompt_parts,
4848- "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.")
4949- end
5050-5151- -- File context
5252- table.insert(prompt_parts, string.format("File: %s (%s)", file_context.filename, file_context.filetype))
5353-5454- -- Selection context if present
5555- if selection then
5656- table.insert(prompt_parts, string.format("Selected lines %d-%d:", selection.start_line, selection.end_line))
5757- table.insert(prompt_parts, "```" .. file_context.filetype)
5858- table.insert(prompt_parts, selection.text)
5959- table.insert(prompt_parts, "```")
6060- end
6161-6262- -- User request
6363- table.insert(prompt_parts, "Request: " .. user_input)
6464-6565- return table.concat(prompt_parts, '\n\n')
6666-end
6767-6868--- Execute claude command
6969-function M.execute_claude(prompt, callback)
7070- -- Alternative 1: Use vim.system (Neovim 0.10+) - cleaner, no shell escaping needed
7171- vim.system({ 'claude', '-p', prompt }, {
7272- text = true
7373- }, function(result)
7474- vim.schedule(function()
7575- if result.code == 0 then
7676- if callback then callback(result.stdout) end
7777- else
7878- vim.notify("Claude error: " .. (result.stderr or "Unknown error"), vim.log.levels.ERROR)
7979- end
8080- end)
8181- end)
8282-end
8383-8484--- Execute claude command with tool permissions for diagnostic fixing
8585-function M.execute_claude_with_tools(prompt, callback)
8686- vim.system({ 'claude', '--allowedTools=Edit,Read', '-p', prompt }, {
8787- text = true
8888- }, function(result)
8989- vim.schedule(function()
9090- if result.code == 0 then
9191- if callback then callback(result.stdout) end
9292- else
9393- vim.notify("Claude error: " .. (result.stderr or "Unknown error"), vim.log.levels.ERROR)
9494- end
9595- end)
9696- end)
9797-end
9898-9999--- Replace selection with new content
100100-function M.replace_selection(selection, new_content)
101101- local lines = vim.split(new_content, '\n')
102102- vim.api.nvim_buf_set_lines(0, selection.start_line - 1, selection.end_line, false, lines)
103103-end
104104-105105--- Check if claude binary exists
106106-function M.claude_available()
107107- return vim.fn.executable('claude') == 1
108108-end
109109-110110-return M
-52
nvim/lua/utils/diagnostic_helpers.lua
···11-local M = {}
22-33--- Get diagnostics for a specific line range
44-function M.get_range_diagnostics(bufnr, start_line, end_line)
55- local all_diagnostics = vim.diagnostic.get(bufnr or 0)
66- local range_diagnostics = {}
77-88- for _, diagnostic in ipairs(all_diagnostics) do
99- -- Convert from 0-indexed to 1-indexed for user-facing line numbers
1010- local diag_line = diagnostic.lnum + 1
1111- if diag_line >= start_line and diag_line <= end_line then
1212- table.insert(range_diagnostics, diagnostic)
1313- end
1414- end
1515-1616- return range_diagnostics
1717-end
1818-1919--- Format diagnostics for Claude prompt
2020-function M.format_diagnostics_for_prompt(diagnostics)
2121- if #diagnostics == 0 then
2222- return "No diagnostics found in the selected range."
2323- end
2424-2525- local severity_names = {
2626- [vim.diagnostic.severity.ERROR] = "ERROR",
2727- [vim.diagnostic.severity.WARN] = "WARNING",
2828- [vim.diagnostic.severity.INFO] = "INFO",
2929- [vim.diagnostic.severity.HINT] = "HINT"
3030- }
3131-3232- local formatted_lines = {}
3333- table.insert(formatted_lines, "Diagnostic Issues:")
3434-3535- for _, diagnostic in ipairs(diagnostics) do
3636- local line_num = diagnostic.lnum + 1 -- Convert to 1-indexed
3737- local severity = severity_names[diagnostic.severity] or "UNKNOWN"
3838- local message = diagnostic.message:gsub("\n", " ") -- Remove newlines from message
3939-4040- table.insert(formatted_lines, string.format("Line %d: [%s] %s", line_num, severity, message))
4141- end
4242-4343- return table.concat(formatted_lines, "\n")
4444-end
4545-4646--- Quick check if any diagnostics exist in range
4747-function M.has_diagnostics(bufnr, start_line, end_line)
4848- local diagnostics = M.get_range_diagnostics(bufnr, start_line, end_line)
4949- return #diagnostics > 0
5050-end
5151-5252-return M