diff --git a/README.md b/README.md index 8998b6f..f2f69e8 100644 --- a/README.md +++ b/README.md @@ -231,6 +231,7 @@ _See [config.lua#L9](./lua/avante/config.lua) for the full config_ auto_set_keymaps = true, auto_apply_diff_after_generation = false, support_paste_from_clipboard = false, + minimize_diff = true, -- Whether to remove unchanged lines when applying a code block }, mappings = { --- @class AvanteConflictMappings diff --git a/lua/avante/config.lua b/lua/avante/config.lua index ff74394..98d5212 100644 --- a/lua/avante/config.lua +++ b/lua/avante/config.lua @@ -120,12 +120,14 @@ M.defaults = { --- Note that avante will safely set these keymap. See https://github.com/yetone/avante.nvim/wiki#keymaps-and-api-i-guess for more details. ---3. auto_set_highlight_group : Whether to automatically set the highlight group for the current line. Default to true. ---4. support_paste_from_clipboard : Whether to support pasting image from clipboard. This will be determined automatically based whether img-clip is available or not. + ---5. minimize_diff : Whether to remove unchanged lines when applying a code block behaviour = { auto_suggestions = false, -- Experimental stage auto_set_highlight_group = true, auto_set_keymaps = true, auto_apply_diff_after_generation = false, support_paste_from_clipboard = false, + minimize_diff = true, }, history = { max_tokens = 4096, diff --git a/lua/avante/sidebar.lua b/lua/avante/sidebar.lua index b9f94dd..50e607f 100644 --- a/lua/avante/sidebar.lua +++ b/lua/avante/sidebar.lua @@ -541,11 +541,68 @@ local function parse_codeblocks(buf) return codeblocks end +---@param original_lines string[] +---@param snippet AvanteCodeSnippet +---@return AvanteCodeSnippet[] +local function minimize_snippet(original_lines, snippet) + local start_line = snippet.range[1] + local end_line = snippet.range[2] + local original_snippet_lines = vim.list_slice(original_lines, start_line, end_line) + local original_snippet_content = table.concat(original_snippet_lines, "\n") + local snippet_content = snippet.content + local snippet_lines = vim.split(snippet_content, "\n") + ---@diagnostic disable-next-line: missing-fields, assign-type-mismatch + local patch = vim.diff( + original_snippet_content, + snippet_content, + { algorithm = "histogram", result_type = "indices", ctxlen = vim.o.scrolloff } + ) ---@type integer[][] + ---@type AvanteCodeSnippet[] + local new_snippets = {} + for _, hunk in ipairs(patch) do + local start_a, count_a, start_b, count_b = unpack(hunk) + ---@type AvanteCodeSnippet + local new_snippet = { + range = { start_line + start_a - 1, start_line + start_a + count_a - 2 }, + content = table.concat(vim.list_slice(snippet_lines, start_b, start_b + count_b - 1), "\n"), + lang = snippet.lang, + explanation = snippet.explanation, + start_line_in_response_buf = snippet.start_line_in_response_buf, + end_line_in_response_buf = snippet.end_line_in_response_buf, + filepath = snippet.filepath, + } + table.insert(new_snippets, new_snippet) + end + return new_snippets +end + +---@param snippets_map table +---@return table +function Sidebar:minimize_snippets(snippets_map) + local original_lines = api.nvim_buf_get_lines(self.code.bufnr, 0, -1, false) + local results = {} + + for filepath, snippets in pairs(snippets_map) do + for _, snippet in ipairs(snippets) do + local new_snippets = minimize_snippet(original_lines, snippet) + if new_snippets then + results[filepath] = results[filepath] or {} + for _, new_snippet in ipairs(new_snippets) do + table.insert(results[filepath], new_snippet) + end + end + end + end + + return results +end + ---@param current_cursor boolean function Sidebar:apply(current_cursor) local response, response_start_line = self:get_content_between_separators() local all_snippets_map = extract_code_snippets_map(response) all_snippets_map = ensure_snippets_no_overlap(all_snippets_map) + if Config.options.behaviour.minimize_diff then all_snippets_map = self:minimize_snippets(all_snippets_map) end local selected_snippets_map = {} if current_cursor then if self.result and self.result.winid then