diff --git a/lua/codetyper/core/diff/patch.lua b/lua/codetyper/core/diff/patch.lua index 836a107..cf3d4c0 100644 --- a/lua/codetyper/core/diff/patch.lua +++ b/lua/codetyper/core/diff/patch.lua @@ -7,14 +7,10 @@ local M = {} +local inject = require("codetyper.inject.inject") local params = require("codetyper.params.agents.patch") local logger = require("codetyper.support.logger") ---- Lazy load inject module to avoid circular requires -local function get_inject_module() - return require("codetyper.inject") -end - --- Lazy load search_replace module local function get_search_replace_module() return require("codetyper.core.diff.search_replace") @@ -630,7 +626,6 @@ function M.apply(patch) end -- Use smart injection module for intelligent import handling - local inject = get_inject_module() local inject_result = nil local has_range = patch.injection_range ~= nil @@ -788,7 +783,7 @@ function M.apply(patch) end -- Use smart injection - handles imports automatically - inject_result = inject.inject(target_bufnr, code_to_inject, inject_opts) + inject_result = inject(target_bufnr, code_to_inject, inject_opts) -- Log injection details pcall(function() diff --git a/lua/codetyper/inject.lua b/lua/codetyper/inject.lua deleted file mode 100644 index 25f12c7..0000000 --- a/lua/codetyper/inject.lua +++ /dev/null @@ -1,266 +0,0 @@ ----@mod codetyper.inject Code injection for Codetyper.nvim - -local M = {} - -local utils = require("codetyper.support.utils") - ---- Inject generated code into target file ----@param target_path string Path to target file ----@param code string Generated code ----@param prompt_type string Type of prompt (refactor, add, document, etc.) -function M.inject_code(target_path, code, prompt_type) - -- Normalize the target path - target_path = vim.fn.fnamemodify(target_path, ":p") - - -- Try to find buffer by path - local target_buf = nil - for _, buf in ipairs(vim.api.nvim_list_bufs()) do - local buf_name = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf), ":p") - if buf_name == target_path then - target_buf = buf - break - end - end - - -- If still not found, open the file - if not target_buf or not vim.api.nvim_buf_is_valid(target_buf) then - -- Check if file exists - if utils.file_exists(target_path) then - vim.cmd("edit " .. vim.fn.fnameescape(target_path)) - target_buf = vim.api.nvim_get_current_buf() - utils.notify("Opened target file: " .. vim.fn.fnamemodify(target_path, ":t")) - else - utils.notify("Target file not found: " .. target_path, vim.log.levels.ERROR) - return - end - end - - if not target_buf then - utils.notify("Target buffer not found", vim.log.levels.ERROR) - return - end - - utils.notify("Injecting code into: " .. vim.fn.fnamemodify(target_path, ":t")) - - -- Different injection strategies based on prompt type - if prompt_type == "refactor" then - M.inject_refactor(target_buf, code) - elseif prompt_type == "add" then - M.inject_add(target_buf, code) - elseif prompt_type == "document" then - M.inject_document(target_buf, code) - else - -- For generic, auto-add instead of prompting - M.inject_add(target_buf, code) - end - - -- Mark buffer as modified and save - vim.bo[target_buf].modified = true - - -- Auto-save the target file - vim.schedule(function() - if vim.api.nvim_buf_is_valid(target_buf) then - local wins = vim.fn.win_findbuf(target_buf) - if #wins > 0 then - vim.api.nvim_win_call(wins[1], function() - vim.cmd("silent! write") - end) - end - end - end) -end - ---- Inject code with strategy and range (used by patch system) ----@param bufnr number Buffer number ----@param code string Generated code ----@param opts table|nil { strategy = "replace"|"insert"|"append", range = { start_line, end_line } (1-based) } ----@return table { imports_added: number, body_lines: number, imports_merged: boolean } -function M.inject(bufnr, code, opts) - opts = opts or {} - local strategy = opts.strategy or "replace" - local range = opts.range - local lines = vim.split(code, "\n", { plain = true }) - local body_lines = #lines - - if not vim.api.nvim_buf_is_valid(bufnr) then - return { imports_added = 0, body_lines = 0, imports_merged = false } - end - - local line_count = vim.api.nvim_buf_line_count(bufnr) - - if strategy == "replace" and range and range.start_line and range.end_line then - local start_0 = math.max(0, range.start_line - 1) - local end_0 = math.min(line_count, range.end_line) - if end_0 < start_0 then - end_0 = start_0 - end - vim.api.nvim_buf_set_lines(bufnr, start_0, end_0, false, lines) - elseif strategy == "insert" and range and range.start_line then - local at_0 = math.max(0, math.min(range.start_line - 1, line_count)) - vim.api.nvim_buf_set_lines(bufnr, at_0, at_0, false, lines) - else - -- append - vim.api.nvim_buf_set_lines(bufnr, line_count, line_count, false, lines) - end - - return { imports_added = 0, body_lines = body_lines, imports_merged = false } -end - ---- Inject code for refactor (replace entire file) ----@param bufnr number Buffer number ----@param code string Generated code -function M.inject_refactor(bufnr, code) - local lines = vim.split(code, "\n", { plain = true }) - - -- Save cursor position - local cursor = nil - local wins = vim.fn.win_findbuf(bufnr) - if #wins > 0 then - cursor = vim.api.nvim_win_get_cursor(wins[1]) - end - - -- Replace buffer content - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) - - -- Restore cursor position if possible - if cursor then - local line_count = vim.api.nvim_buf_line_count(bufnr) - cursor[1] = math.min(cursor[1], line_count) - pcall(vim.api.nvim_win_set_cursor, wins[1], cursor) - end - - utils.notify("Code refactored", vim.log.levels.INFO) -end - ---- Inject code for add (append at cursor or end) ----@param bufnr number Buffer number ----@param code string Generated code -function M.inject_add(bufnr, code) - local lines = vim.split(code, "\n", { plain = true }) - - -- Try to find a window displaying this buffer to get cursor position - local insert_line - local wins = vim.fn.win_findbuf(bufnr) - if #wins > 0 then - local cursor = vim.api.nvim_win_get_cursor(wins[1]) - insert_line = cursor[1] - else - insert_line = vim.api.nvim_buf_line_count(bufnr) - end - - -- Insert lines at position - vim.api.nvim_buf_set_lines(bufnr, insert_line, insert_line, false, lines) - - utils.notify("Code added at line " .. (insert_line + 1), vim.log.levels.INFO) -end - ---- Inject documentation ----@param bufnr number Buffer number ----@param code string Generated documentation -function M.inject_document(bufnr, code) - -- Documentation typically goes above the current function/class - -- For simplicity, insert at cursor position - M.inject_add(bufnr, code) - utils.notify("Documentation added", vim.log.levels.INFO) -end - ---- Generic injection (prompt user for action) ----@param bufnr number Buffer number ----@param code string Generated code -function M.inject_generic(bufnr, code) - local actions = { - "Replace entire file", - "Insert at cursor", - "Append to end", - "Copy to clipboard", - "Cancel", - } - - vim.ui.select(actions, { - prompt = "How to inject the generated code?", - }, function(choice) - if not choice then - return - end - - if choice == "Replace entire file" then - M.inject_refactor(bufnr, code) - elseif choice == "Insert at cursor" then - M.inject_add(bufnr, code) - elseif choice == "Append to end" then - local lines = vim.split(code, "\n", { plain = true }) - local line_count = vim.api.nvim_buf_line_count(bufnr) - vim.api.nvim_buf_set_lines(bufnr, line_count, line_count, false, lines) - utils.notify("Code appended to end", vim.log.levels.INFO) - elseif choice == "Copy to clipboard" then - vim.fn.setreg("+", code) - utils.notify("Code copied to clipboard", vim.log.levels.INFO) - end - end) -end - ---- Preview code in a floating window before injection ----@param code string Generated code ----@param callback fun(action: string) Callback with selected action -function M.preview(code, callback) - local codetyper = require("codetyper") - local config = codetyper.get_config() - - local lines = vim.split(code, "\n", { plain = true }) - - -- Create buffer for preview - local buf = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) - - -- Calculate window size - local width = math.min(80, vim.o.columns - 10) - local height = math.min(#lines + 2, vim.o.lines - 10) - - -- Create floating window - local win = vim.api.nvim_open_win(buf, true, { - relative = "editor", - width = width, - height = height, - row = math.floor((vim.o.lines - height) / 2), - col = math.floor((vim.o.columns - width) / 2), - style = "minimal", - border = config.window.border, - title = " Generated Code Preview ", - title_pos = "center", - }) - - -- Set buffer options - vim.bo[buf].modifiable = false - vim.bo[buf].bufhidden = "wipe" - - -- Add keymaps for actions - local opts = { buffer = buf, noremap = true, silent = true } - - vim.keymap.set("n", "q", function() - vim.api.nvim_win_close(win, true) - callback("cancel") - end, opts) - - vim.keymap.set("n", "", function() - vim.api.nvim_win_close(win, true) - callback("inject") - end, opts) - - vim.keymap.set("n", "y", function() - vim.fn.setreg("+", code) - utils.notify("Copied to clipboard") - end, opts) - - -- Show help in command line - vim.api.nvim_echo({ - { "Press ", "Normal" }, - { "", "Keyword" }, - { " to inject, ", "Normal" }, - { "y", "Keyword" }, - { " to copy, ", "Normal" }, - { "q", "Keyword" }, - { " to cancel", "Normal" }, - }, false, {}) -end - -return M diff --git a/lua/codetyper/inject/inject.lua b/lua/codetyper/inject/inject.lua new file mode 100644 index 0000000..bb41913 --- /dev/null +++ b/lua/codetyper/inject/inject.lua @@ -0,0 +1,38 @@ +local M = {} +--- Inject code with strategy and range (used by patch system) +---@param bufnr number Buffer number +---@param code string Generated code +---@param opts table|nil { strategy = "replace"|"insert"|"append", range = { start_line, end_line } (1-based) } +---@return table { imports_added: number, body_lines: number, imports_merged: boolean } +function M.inject(bufnr, code, opts) + opts = opts or {} + local strategy = opts.strategy or "replace" + local range = opts.range + local lines = vim.split(code, "\n", { plain = true }) + local body_lines = #lines + + if not vim.api.nvim_buf_is_valid(bufnr) then + return { imports_added = 0, body_lines = 0, imports_merged = false } + end + + local line_count = vim.api.nvim_buf_line_count(bufnr) + + if strategy == "replace" and range and range.start_line and range.end_line then + local start_0 = math.max(0, range.start_line - 1) + local end_0 = math.min(line_count, range.end_line) + if end_0 < start_0 then + end_0 = start_0 + end + vim.api.nvim_buf_set_lines(bufnr, start_0, end_0, false, lines) + elseif strategy == "insert" and range and range.start_line then + local at_0 = math.max(0, math.min(range.start_line - 1, line_count)) + vim.api.nvim_buf_set_lines(bufnr, at_0, at_0, false, lines) + else + -- append + vim.api.nvim_buf_set_lines(bufnr, line_count, line_count, false, lines) + end + + return { imports_added = 0, body_lines = body_lines, imports_merged = false } +end + +return M diff --git a/lua/codetyper/inject/injectCode.lua b/lua/codetyper/inject/injectCode.lua new file mode 100644 index 0000000..88cd5f0 --- /dev/null +++ b/lua/codetyper/inject/injectCode.lua @@ -0,0 +1,75 @@ +local M = {} + +local utils = require("codetyper.support.utils") + +local inject_refactor = require("codetyper.inject.inject_refactor") +local inject_add = require("codetyper.inject.inject_add") +local inject_document = require("codetyper.inject.inject_document") + +--- Inject generated code into target file +---@param target_path string Path to target file +---@param code string Generated code +---@param prompt_type string Type of prompt (refactor, add, document, etc.) +function M.inject_code(target_path, code, prompt_type) + -- Normalize the target path + target_path = vim.fn.fnamemodify(target_path, ":p") + + -- Try to find buffer by path + local target_buf = nil + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + local buf_name = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf), ":p") + if buf_name == target_path then + target_buf = buf + break + end + end + + -- If still not found, open the file + if not target_buf or not vim.api.nvim_buf_is_valid(target_buf) then + -- Check if file exists + if utils.file_exists(target_path) then + vim.cmd("edit " .. vim.fn.fnameescape(target_path)) + target_buf = vim.api.nvim_get_current_buf() + utils.notify("Opened target file: " .. vim.fn.fnamemodify(target_path, ":t")) + else + utils.notify("Target file not found: " .. target_path, vim.log.levels.ERROR) + return + end + end + + if not target_buf then + utils.notify("Target buffer not found", vim.log.levels.ERROR) + return + end + + utils.notify("Injecting code into: " .. vim.fn.fnamemodify(target_path, ":t")) + + -- Different injection strategies based on prompt type + if prompt_type == "refactor" then + inject_refactor(target_buf, code) + elseif prompt_type == "add" then + inject_add(target_buf, code) + elseif prompt_type == "document" then + inject_document(target_buf, code) + else + -- For generic, auto-add instead of prompting + inject_add(target_buf, code) + end + + -- Mark buffer as modified and save + vim.bo[target_buf].modified = true + + -- Auto-save the target file + vim.schedule(function() + if vim.api.nvim_buf_is_valid(target_buf) then + local wins = vim.fn.win_findbuf(target_buf) + if #wins > 0 then + vim.api.nvim_win_call(wins[1], function() + vim.cmd("silent! write") + end) + end + end + end) +end + +return M diff --git a/lua/codetyper/inject/inject_add.lua b/lua/codetyper/inject/inject_add.lua new file mode 100644 index 0000000..772795d --- /dev/null +++ b/lua/codetyper/inject/inject_add.lua @@ -0,0 +1,25 @@ +local M = {} + +--- Inject code for add (append at cursor or end) +---@param bufnr number Buffer number +---@param code string Generated code +function M.inject_add(bufnr, code) + local lines = vim.split(code, "\n", { plain = true }) + + -- Try to find a window displaying this buffer to get cursor position + local insert_line + local wins = vim.fn.win_findbuf(bufnr) + if #wins > 0 then + local cursor = vim.api.nvim_win_get_cursor(wins[1]) + insert_line = cursor[1] + else + insert_line = vim.api.nvim_buf_line_count(bufnr) + end + + -- Insert lines at position + vim.api.nvim_buf_set_lines(bufnr, insert_line, insert_line, false, lines) + + utils.notify("Code added at line " .. (insert_line + 1), vim.log.levels.INFO) +end + +return M diff --git a/lua/codetyper/inject/inject_document.lua b/lua/codetyper/inject/inject_document.lua new file mode 100644 index 0000000..2b39176 --- /dev/null +++ b/lua/codetyper/inject/inject_document.lua @@ -0,0 +1,14 @@ +local M = {} +local inject_add = require("codetyper.inject.inject_add") + +--- Inject documentation +---@param bufnr number Buffer number +---@param code string Generated documentation +function M.inject_document(bufnr, code) + -- Documentation typically goes above the current function/class + -- For simplicity, insert at cursor position + inject_add(bufnr, code) + utils.notify("Documentation added", vim.log.levels.INFO) +end + +return M diff --git a/lua/codetyper/inject/inject_generic.lua b/lua/codetyper/inject/inject_generic.lua new file mode 100644 index 0000000..b3c2488 --- /dev/null +++ b/lua/codetyper/inject/inject_generic.lua @@ -0,0 +1,40 @@ +local M = {} +local inject_refactor = require("codetyper.inject.inject_refactor") +local inject_add = require("codetyper.inject.inject_add") + +--- Generic injection (prompt user for action) +---@param bufnr number Buffer number +---@param code string Generated code +function M.inject_generic(bufnr, code) + local actions = { + "Replace entire file", + "Insert at cursor", + "Append to end", + "Copy to clipboard", + "Cancel", + } + + vim.ui.select(actions, { + prompt = "How to inject the generated code?", + }, function(choice) + if not choice then + return + end + + if choice == "Replace entire file" then + inject_refactor(bufnr, code) + elseif choice == "Insert at cursor" then + inject_add(bufnr, code) + elseif choice == "Append to end" then + local lines = vim.split(code, "\n", { plain = true }) + local line_count = vim.api.nvim_buf_line_count(bufnr) + vim.api.nvim_buf_set_lines(bufnr, line_count, line_count, false, lines) + utils.notify("Code appended to end", vim.log.levels.INFO) + elseif choice == "Copy to clipboard" then + vim.fn.setreg("+", code) + utils.notify("Code copied to clipboard", vim.log.levels.INFO) + end + end) +end + +return M diff --git a/lua/codetyper/inject/inject_refactor.lua b/lua/codetyper/inject/inject_refactor.lua new file mode 100644 index 0000000..1a7d2e8 --- /dev/null +++ b/lua/codetyper/inject/inject_refactor.lua @@ -0,0 +1,29 @@ +local M = {} + +--- Inject code for refactor (replace entire file) +---@param bufnr number Buffer number +---@param code string Generated code +function M.inject_refactor(bufnr, code) + local lines = vim.split(code, "\n", { plain = true }) + + -- Save cursor position + local cursor = nil + local wins = vim.fn.win_findbuf(bufnr) + if #wins > 0 then + cursor = vim.api.nvim_win_get_cursor(wins[1]) + end + + -- Replace buffer content + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) + + -- Restore cursor position if possible + if cursor then + local line_count = vim.api.nvim_buf_line_count(bufnr) + cursor[1] = math.min(cursor[1], line_count) + pcall(vim.api.nvim_win_set_cursor, wins[1], cursor) + end + + utils.notify("Code refactored", vim.log.levels.INFO) +end + +return M diff --git a/lua/codetyper/inject/preview.lua b/lua/codetyper/inject/preview.lua new file mode 100644 index 0000000..5ddb8d9 --- /dev/null +++ b/lua/codetyper/inject/preview.lua @@ -0,0 +1,68 @@ +local M = {} +local utils = require("codetyper.support.utils") + +--- Preview code in a floating window before injection +---@param code string Generated code +---@param callback fun(action: string) Callback with selected action +function M.preview(code, callback) + local codetyper = require("codetyper") + local config = codetyper.get_config() + + local lines = vim.split(code, "\n", { plain = true }) + + -- Create buffer for preview + local buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) + + -- Calculate window size + local width = math.min(80, vim.o.columns - 10) + local height = math.min(#lines + 2, vim.o.lines - 10) + + -- Create floating window + local win = vim.api.nvim_open_win(buf, true, { + relative = "editor", + width = width, + height = height, + row = math.floor((vim.o.lines - height) / 2), + col = math.floor((vim.o.columns - width) / 2), + style = "minimal", + border = config.window.border, + title = " Generated Code Preview ", + title_pos = "center", + }) + + -- Set buffer options + vim.bo[buf].modifiable = false + vim.bo[buf].bufhidden = "wipe" + + -- Add keymaps for actions + local opts = { buffer = buf, noremap = true, silent = true } + + vim.keymap.set("n", "q", function() + vim.api.nvim_win_close(win, true) + callback("cancel") + end, opts) + + vim.keymap.set("n", "", function() + vim.api.nvim_win_close(win, true) + callback("inject") + end, opts) + + vim.keymap.set("n", "y", function() + vim.fn.setreg("+", code) + utils.notify("Copied to clipboard") + end, opts) + + -- Show help in command line + vim.api.nvim_echo({ + { "Press ", "Normal" }, + { "", "Keyword" }, + { " to inject, ", "Normal" }, + { "y", "Keyword" }, + { " to copy, ", "Normal" }, + { "q", "Keyword" }, + { " to cancel", "Normal" }, + }, false, {}) +end + +return M diff --git a/lua/codetyper/parser.lua b/lua/codetyper/parser.lua index 42dce05..7ae9804 100644 --- a/lua/codetyper/parser.lua +++ b/lua/codetyper/parser.lua @@ -4,98 +4,8 @@ local M = {} local utils = require("codetyper.support.utils") local logger = require("codetyper.support.logger") - --- Get current codetyper configuration at call time -local function get_config() - local ok, codetyper = pcall(require, "codetyper") - if ok and codetyper.get_config then - return codetyper.get_config() or {} - end - -- Fall back to defaults if codetyper isn't available - local defaults = require("codetyper.config.defaults") - return defaults.get_defaults() -end - ---- Find all prompts in buffer content ----@param content string Buffer content ----@param open_tag string Opening tag ----@param close_tag string Closing tag ----@return CoderPrompt[] List of found prompts -function M.find_prompts(content, open_tag, close_tag) - logger.func_entry("parser", "find_prompts", { - content_length = #content, - open_tag = open_tag, - close_tag = close_tag, - }) - - local prompts = {} - local escaped_open = utils.escape_pattern(open_tag) - local escaped_close = utils.escape_pattern(close_tag) - - local lines = vim.split(content, "\n", { plain = true }) - local in_prompt = false - local current_prompt = nil - local prompt_content = {} - - logger.debug("parser", "find_prompts: parsing " .. #lines .. " lines") - - for line_num, line in ipairs(lines) do - if not in_prompt then - -- Look for opening tag - local start_col = line:find(escaped_open) - if start_col then - logger.debug("parser", "find_prompts: found opening tag at line " .. line_num .. ", col " .. start_col) - in_prompt = true - current_prompt = { - start_line = line_num, - start_col = start_col, - content = "", - } - -- Get content after opening tag on same line - local after_tag = line:sub(start_col + #open_tag) - local end_col = after_tag:find(escaped_close) - if end_col then - -- Single line prompt - current_prompt.content = after_tag:sub(1, end_col - 1) - current_prompt.end_line = line_num - current_prompt.end_col = start_col + #open_tag + end_col + #close_tag - 2 - table.insert(prompts, current_prompt) - logger.debug("parser", "find_prompts: single-line prompt completed at line " .. line_num) - in_prompt = false - current_prompt = nil - else - table.insert(prompt_content, after_tag) - end - end - else - -- Look for closing tag - local end_col = line:find(escaped_close) - if end_col then - -- Found closing tag - local before_tag = line:sub(1, end_col - 1) - table.insert(prompt_content, before_tag) - current_prompt.content = table.concat(prompt_content, "\n") - current_prompt.end_line = line_num - current_prompt.end_col = end_col + #close_tag - 1 - table.insert(prompts, current_prompt) - logger.debug( - "parser", - "find_prompts: multi-line prompt completed at line " .. line_num .. ", total lines: " .. #prompt_content - ) - in_prompt = false - current_prompt = nil - prompt_content = {} - else - table.insert(prompt_content, line) - end - end - end - - logger.debug("parser", "find_prompts: found " .. #prompts .. " prompts total") - logger.func_exit("parser", "find_prompts", "found " .. #prompts .. " prompts") - - return prompts -end +local get_config = require("codetyper.utils.get_config").get_config +local find_prompts = require("codetyper.parser.find_prompts") --- Find prompts in a buffer ---@param bufnr number Buffer number @@ -112,7 +22,7 @@ function M.find_prompts_in_buffer(bufnr) ) local cfg = get_config() - local result = M.find_prompts(content, cfg.patterns.open_tag, cfg.patterns.close_tag) + local result = find_prompts(content, cfg.patterns.open_tag, cfg.patterns.close_tag) logger.func_exit("parser", "find_prompts_in_buffer", "found " .. #result .. " prompts") return result diff --git a/lua/codetyper/parser/find_prompts.lua b/lua/codetyper/parser/find_prompts.lua new file mode 100644 index 0000000..cc9e584 --- /dev/null +++ b/lua/codetyper/parser/find_prompts.lua @@ -0,0 +1,85 @@ +local utils = require("codetyper.support.utils") +local logger = require("codetyper.support.logger") + +--- Find all prompts in buffer content +---@param content string Buffer content +---@param open_tag string Opening tag +---@param close_tag string Closing tag +---@return CoderPrompt[] List of found prompts +function find_prompts(content, open_tag, close_tag) + logger.func_entry("parser", "find_prompts", { + content_length = #content, + open_tag = open_tag, + close_tag = close_tag, + }) + + local prompts = {} + local escaped_open = utils.escape_pattern(open_tag) + local escaped_close = utils.escape_pattern(close_tag) + + local lines = vim.split(content, "\n", { plain = true }) + local in_prompt = false + local current_prompt = nil + local prompt_content = {} + + logger.debug("parser", "find_prompts: parsing " .. #lines .. " lines") + + for line_num, line in ipairs(lines) do + if not in_prompt then + -- Look for opening tag + local start_col = line:find(escaped_open) + if start_col then + logger.debug("parser", "find_prompts: found opening tag at line " .. line_num .. ", col " .. start_col) + in_prompt = true + current_prompt = { + start_line = line_num, + start_col = start_col, + content = "", + } + -- Get content after opening tag on same line + local after_tag = line:sub(start_col + #open_tag) + local end_col = after_tag:find(escaped_close) + if end_col then + -- Single line prompt + current_prompt.content = after_tag:sub(1, end_col - 1) + current_prompt.end_line = line_num + current_prompt.end_col = start_col + #open_tag + end_col + #close_tag - 2 + table.insert(prompts, current_prompt) + logger.debug("parser", "find_prompts: single-line prompt completed at line " .. line_num) + in_prompt = false + current_prompt = nil + else + table.insert(prompt_content, after_tag) + end + end + else + -- Look for closing tag + local end_col = line:find(escaped_close) + if end_col then + -- Found closing tag + local before_tag = line:sub(1, end_col - 1) + table.insert(prompt_content, before_tag) + current_prompt.content = table.concat(prompt_content, "\n") + current_prompt.end_line = line_num + current_prompt.end_col = end_col + #close_tag - 1 + table.insert(prompts, current_prompt) + logger.debug( + "parser", + "find_prompts: multi-line prompt completed at line " .. line_num .. ", total lines: " .. #prompt_content + ) + in_prompt = false + current_prompt = nil + prompt_content = {} + else + table.insert(prompt_content, line) + end + end + end + + logger.debug("parser", "find_prompts: found " .. #prompts .. " prompts total") + logger.func_exit("parser", "find_prompts", "found " .. #prompts .. " prompts") + + return prompts +end + +return find_prompts diff --git a/lua/codetyper/utils/get_config.lua b/lua/codetyper/utils/get_config.lua new file mode 100644 index 0000000..fd80f32 --- /dev/null +++ b/lua/codetyper/utils/get_config.lua @@ -0,0 +1,14 @@ +local M = {} + +-- Get current codetyper configuration at call time +function M.get_config() + local ok, codetyper = pcall(require, "codetyper") + if ok and codetyper.get_config then + return codetyper.get_config() or {} + end + -- Fall back to defaults if codetyper isn't available + local defaults = require("codetyper.config.defaults") + return defaults.get_defaults() +end + +return M diff --git a/lua/codetyper/window/init.lua b/lua/codetyper/window/init.lua new file mode 100644 index 0000000..8728417 --- /dev/null +++ b/lua/codetyper/window/init.lua @@ -0,0 +1 @@ +// TODO: Migrate the prompt window here to centralized the logic