From 5cf85d59bd54f060948d4e60e9b7ed2b9d2d50a3 Mon Sep 17 00:00:00 2001 From: yetone Date: Fri, 30 Aug 2024 20:43:26 +0800 Subject: [PATCH] fix: ensure there is no overlap between code snippets (#396) --- lua/avante/llm.lua | 12 +++++----- lua/avante/sidebar.lua | 53 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/lua/avante/llm.lua b/lua/avante/llm.lua index d42a6b5..e6a1cff 100644 --- a/lua/avante/llm.lua +++ b/lua/avante/llm.lua @@ -16,7 +16,7 @@ M.CANCEL_PATTERN = "AvanteLLMEscape" -- Copy from: https://github.com/Doriandarko/claude-engineer/blob/15c94963cbf9d01b8ae7bbb5d42d7025aa0555d5/main.py#L276 ---@alias AvanteBasePrompt string local planning_mode_system_prompt_tpl = [[ -You are an AI coding agent that generates code according to the instructions. Follow these steps: +You are an excellent programming expert and your primary task is to generate code according to the instructions. Follow these steps: 1. Review the entire file content to understand the context: ${file_content} @@ -40,12 +40,12 @@ ${full_file_contents_context} - Include enough context to uniquely identify the code to be changed - Provide the exact replacement code, maintaining correct INDENTATION and FORMATTING - Focus on specific, targeted changes rather than large, sweeping modifications - - The content in the SEARCH tag MUST NOT contain any of your generated content + - The content in the SEARCH tag MUST NOT contain any of your generated content. Do not be lazy! - The content in the SEARCH tag MUST be based on the original content of the source file - The content in the SEARCH tag needs to ensure a certain context to guarantee its UNIQUENESS - - The content in the REPLACE tag should also correspond to the context of the SEARCH tag - - There should be NO OVERLAP between the code of each SEARCH tag. - - DO NOT use ``` to wrap code blocks + - There should be NO OVERLAP between the code of each SEARCH tag. Do not be lazy! + - Be sure to ensure that there are NO SYNTAX ERRORS OR FORMATTING ERRORS after the SEARCH part in the source code is replaced by the REPLACE part! Do not be lazy! + - DO NOT use ``` to wrap code blocks, Do not be lazy! 8. Ensure that your SEARCH/REPLACE blocks: - Address all relevant aspects of the instructions @@ -69,7 +69,7 @@ If no changes are needed, return an empty list. ]] local editing_mode_system_prompt_tpl = [[ -You are an AI coding agent that generates code according to the instructions. Follow these steps: +You are an excellent programming expert and your primary task is to generate code according to the instructions. Follow these steps: 1. Review the entire file content to understand the context: ${file_content} diff --git a/lua/avante/sidebar.lua b/lua/avante/sidebar.lua index 7ffabe2..9efca53 100644 --- a/lua/avante/sidebar.lua +++ b/lua/avante/sidebar.lua @@ -243,11 +243,18 @@ local function transform_result_content(original_content, result_content, code_l } end -local searching_hint = "\n 🔍 Searching..." +local searching_hints = { "\n 🔍 Searching...", "\n 🔍 Searching...", "\n 🔍 Searching..." } +local searching_hint_idx = 1 ---@param replacement AvanteReplacementResult ---@return string local function generate_display_content(replacement) + local searching_hint = searching_hints[searching_hint_idx] + if searching_hint_idx >= #searching_hints then + searching_hint_idx = 1 + else + searching_hint_idx = searching_hint_idx + 1 + end if replacement.is_searching then return table.concat( vim.list_slice(vim.split(replacement.content, "\n"), 1, replacement.last_search_tag_start_line - 1), @@ -318,6 +325,49 @@ local function extract_code_snippets(response_content) return snippets end +---@param snippets AvanteCodeSnippet[] +---@return AvanteCodeSnippet[] +local function ensure_snippets_no_overlap(original_content, snippets) + table.sort(snippets, function(a, b) + return a.range[1] < b.range[1] + end) + + local original_lines = vim.split(original_content, "\n") + + local result = {} + local last_end_line = 0 + for _, snippet in ipairs(snippets) do + if snippet.range[1] > last_end_line then + table.insert(result, snippet) + last_end_line = snippet.range[2] + else + local snippet_lines = vim.split(snippet.content, "\n") + -- Trim the overlapping part + local new_start_line = nil + for i = snippet.range[1], math.min(snippet.range[2], last_end_line) do + if + Utils.remove_indentation(original_lines[i]) + == Utils.remove_indentation(snippet_lines[i - snippet.range[1] + 1]) + then + new_start_line = i + 1 + else + break + end + end + if new_start_line ~= nil then + snippet.content = table.concat(vim.list_slice(snippet_lines, new_start_line - snippet.range[1] + 1), "\n") + snippet.range[1] = new_start_line + table.insert(result, snippet) + last_end_line = snippet.range[2] + else + Utils.error("Failed to ensure snippets no overlap", { once = true, title = "Avante" }) + end + end + end + + return result +end + local function get_conflict_content(content, snippets) -- sort snippets by start_line table.sort(snippets, function(a, b) @@ -421,6 +471,7 @@ function Sidebar:apply(current_cursor) local content = table.concat(Utils.get_buf_lines(0, -1, self.code.bufnr), "\n") local response, response_start_line = self:get_content_between_separators() local snippets = extract_code_snippets(response) + snippets = ensure_snippets_no_overlap(content, snippets) if current_cursor then if self.result and self.result.winid then local cursor_line = Utils.get_cursor_pos(self.result.winid)