From 9489f841330931bf544365d48cf4355ba340f3ce Mon Sep 17 00:00:00 2001 From: Cameron Date: Mon, 23 Dec 2024 23:49:46 +0100 Subject: [PATCH] Revert "Add ability to revert hunk" --- lua/neogit/buffers/commit_view/init.lua | 2 +- lua/neogit/buffers/status/actions.lua | 25 +++++++--------- lua/neogit/lib/git/diff.lua | 7 ----- lua/neogit/lib/git/index.lua | 36 +++++++++++++++-------- lua/neogit/lib/git/revert.lua | 5 ---- lua/neogit/lib/ui/init.lua | 11 +++++-- lua/neogit/popups/revert/actions.lua | 4 --- lua/neogit/popups/revert/init.lua | 1 - tests/specs/neogit/lib/git/index_spec.lua | 8 +++-- tests/specs/neogit/lib/git/log_spec.lua | 3 -- 10 files changed, 48 insertions(+), 54 deletions(-) diff --git a/lua/neogit/buffers/commit_view/init.lua b/lua/neogit/buffers/commit_view/init.lua index 9561771d4..90942a931 100644 --- a/lua/neogit/buffers/commit_view/init.lua +++ b/lua/neogit/buffers/commit_view/init.lua @@ -290,7 +290,7 @@ function M:open(kind) end), [popups.mapping_for("RemotePopup")] = popups.open("remote"), [popups.mapping_for("RevertPopup")] = popups.open("revert", function(p) - p { commits = { self.commit_info.oid }, item = self.buffer.ui:get_hunk_or_filename_under_cursor() } + p { commits = { self.commit_info.oid } } end), [popups.mapping_for("ResetPopup")] = popups.open("reset", function(p) p { commit = self.commit_info.oid } diff --git a/lua/neogit/buffers/status/actions.lua b/lua/neogit/buffers/status/actions.lua index d6993ef00..0a52fbdf9 100644 --- a/lua/neogit/buffers/status/actions.lua +++ b/lua/neogit/buffers/status/actions.lua @@ -120,8 +120,7 @@ M.v_discard = function(self) for _, hunk in ipairs(hunks) do table.insert(invalidated_diffs, "*:" .. item.name) table.insert(patches, function() - local patch = - git.index.generate_patch(hunk, { from = hunk.from, to = hunk.to, reverse = true }) + local patch = git.index.generate_patch(item, hunk, hunk.from, hunk.to, true) logger.debug(("Discarding Patch: %s"):format(patch)) @@ -232,7 +231,7 @@ M.v_stage = function(self) if #hunks > 0 then for _, hunk in ipairs(hunks) do - table.insert(patches, git.index.generate_patch(hunk.hunk, { from = hunk.from, to = hunk.to })) + table.insert(patches, git.index.generate_patch(item, hunk, hunk.from, hunk.to)) end else if section.name == "unstaged" then @@ -282,10 +281,7 @@ M.v_unstage = function(self) if #hunks > 0 then for _, hunk in ipairs(hunks) do - table.insert( - patches, - git.index.generate_patch(hunk, { from = hunk.from, to = hunk.to, reverse = true }) - ) + table.insert(patches, git.index.generate_patch(item, hunk, hunk.from, hunk.to, true)) end else table.insert(files, item.escaped_path) @@ -785,7 +781,7 @@ M.n_discard = function(self) local hunk = self.buffer.ui:item_hunks(selection.item, selection.first_line, selection.last_line, false)[1] - local patch = git.index.generate_patch(hunk, { from = hunk.from, to = hunk.to, reverse = true }) + local patch = git.index.generate_patch(selection.item, hunk, hunk.from, hunk.to, true) if section == "untracked" then message = "Discard hunk?" @@ -793,8 +789,9 @@ M.n_discard = function(self) local hunks = self.buffer.ui:item_hunks(selection.item, selection.first_line, selection.last_line, false) - local patch = - git.index.generate_patch(hunks[1], { from = hunks[1].from, to = hunks[1].to, reverse = true }) + local patch = git.index.generate_patch(selection.item, hunks[1], hunks[1].from, hunks[1].to, true) + + git.index.apply(patch, { reverse = true }) git.index.apply(patch, { reverse = true }) end refresh = { update_diffs = { "untracked:" .. selection.item.name } } @@ -1095,7 +1092,7 @@ M.n_stage = function(self) local item = self.buffer.ui:get_item_under_cursor() assert(item, "Item cannot be nil") - local patch = git.index.generate_patch(stagable.hunk) + local patch = git.index.generate_patch(item, stagable.hunk, stagable.hunk.from, stagable.hunk.to) git.index.apply(patch, { cached = true }) self:dispatch_refresh({ update_diffs = { "*:" .. item.escaped_path } }, "n_stage") elseif stagable.filename then @@ -1169,10 +1166,8 @@ M.n_unstage = function(self) if unstagable.hunk then local item = self.buffer.ui:get_item_under_cursor() assert(item, "Item cannot be nil") - local patch = git.index.generate_patch( - unstagable.hunk, - { from = unstagable.hunk.from, to = unstagable.hunk.to, reverse = true } - ) + local patch = + git.index.generate_patch(item, unstagable.hunk, unstagable.hunk.from, unstagable.hunk.to, true) git.index.apply(patch, { cached = true, reverse = true }) self:dispatch_refresh({ update_diffs = { "*:" .. item.escaped_path } }, "n_unstage") diff --git a/lua/neogit/lib/git/diff.lua b/lua/neogit/lib/git/diff.lua index d8c514975..15bea3182 100644 --- a/lua/neogit/lib/git/diff.lua +++ b/lua/neogit/lib/git/diff.lua @@ -24,14 +24,12 @@ local sha256 = vim.fn.sha256 ---@field deletions number --- ---@class Hunk ----@field file string ---@field index_from number ---@field index_len number ---@field diff_from number ---@field diff_to number ---@field first number First line number in buffer ---@field last number Last line number in buffer ----@field lines string[] --- ---@class DiffStagedStats ---@field summary string @@ -226,11 +224,6 @@ local function parse_diff(raw_diff, raw_stats) local file = build_file(header, kind) local stats = parse_diff_stats(raw_stats or {}) - util.map(hunks, function(hunk) - hunk.file = file - return hunk - end) - return { ---@type Diff kind = kind, lines = lines, diff --git a/lua/neogit/lib/git/index.lua b/lua/neogit/lib/git/index.lua index 54837376e..35b9c8cfe 100644 --- a/lua/neogit/lib/git/index.lua +++ b/lua/neogit/lib/git/index.lua @@ -6,15 +6,19 @@ local util = require("neogit.lib.util") local M = {} ---Generates a patch that can be applied to index +---@param item any ---@param hunk Hunk ----@param opts table|nil +---@param from number +---@param to number +---@param reverse boolean|nil ---@return string -function M.generate_patch(hunk, opts) - opts = opts or { reverse = false, cached = false, index = false } - local reverse = opts.reverse +function M.generate_patch(item, hunk, from, to, reverse) + reverse = reverse or false - local from = opts.from or 1 - local to = opts.to or (hunk.diff_to - hunk.diff_from) + if not from and not to then + from = hunk.diff_from + 1 + to = hunk.diff_to + end assert(from <= to, string.format("from must be less than or equal to to %d %d", from, to)) if from > to then @@ -25,31 +29,35 @@ function M.generate_patch(hunk, opts) local len_start = hunk.index_len local len_offset = 0 - for k, line in pairs(hunk.lines) do - local operand, l = line:match("^([+ -])(.*)") + -- + 1 skips the hunk header, since we construct that manually afterwards + -- TODO: could use `hunk.lines` instead if this is only called with the `SelectedHunk` type + for k = hunk.diff_from + 1, hunk.diff_to do + local v = item.diff.lines[k] + local operand, line = v:match("^([+ -])(.*)") + if operand == "+" or operand == "-" then if from <= k and k <= to then len_offset = len_offset + (operand == "+" and 1 or -1) - table.insert(diff_content, line) + table.insert(diff_content, v) else -- If we want to apply the patch normally, we need to include every `-` line we skip as a normal line, -- since we want to keep that line. if not reverse then if operand == "-" then - table.insert(diff_content, " " .. l) + table.insert(diff_content, " " .. line) end -- If we want to apply the patch in reverse, we need to include every `+` line we skip as a normal line, since -- it's unchanged as far as the diff is concerned and should not be reversed. -- We also need to adapt the original line offset based on if we skip or not elseif reverse then if operand == "+" then - table.insert(diff_content, " " .. l) + table.insert(diff_content, " " .. line) end len_start = len_start + (operand == "-" and -1 or 1) end end else - table.insert(diff_content, line) + table.insert(diff_content, v) end end @@ -60,7 +68,9 @@ function M.generate_patch(hunk, opts) ) local worktree_root = git.repo.worktree_root - local path = Path:new(hunk.file):make_relative(worktree_root) + + assert(item.absolute_path, "Item is not a path") + local path = Path:new(item.absolute_path):make_relative(worktree_root) table.insert(diff_content, 1, string.format("+++ b/%s", path)) table.insert(diff_content, 1, string.format("--- a/%s", path)) diff --git a/lua/neogit/lib/git/revert.lua b/lua/neogit/lib/git/revert.lua index b84ee8921..797ca36be 100644 --- a/lua/neogit/lib/git/revert.lua +++ b/lua/neogit/lib/git/revert.lua @@ -16,11 +16,6 @@ function M.commits(commits, args) end end -function M.hunk(hunk, _) - local patch = git.index.generate_patch(hunk, { reverse = true }) - git.index.apply(patch, { reverse = true }) -end - function M.continue() git.cli.revert.continue.no_edit.call { pty = true } end diff --git a/lua/neogit/lib/ui/init.lua b/lua/neogit/lib/ui/init.lua index 88cd772fe..95b2d5e0e 100644 --- a/lua/neogit/lib/ui/init.lua +++ b/lua/neogit/lib/ui/init.lua @@ -182,19 +182,25 @@ function Ui:item_hunks(item, first_line, last_line, partial) if not item.folded and item.diff.hunks then for _, h in ipairs(item.diff.hunks) do - if h.first <= first_line and h.last >= last_line then + if h.first <= last_line and h.last >= first_line then local from, to if partial then + local cursor_offset = first_line - h.first local length = last_line - first_line - from = first_line - h.first + from = h.diff_from + cursor_offset to = from + length else from = h.diff_from + 1 to = h.diff_to end + local hunk_lines = {} + for i = from, to do + table.insert(hunk_lines, item.diff.lines[i]) + end + -- local conflict = false -- for _, n in ipairs(conflict_markers) do -- if from <= n and n <= to then @@ -208,6 +214,7 @@ function Ui:item_hunks(item, first_line, last_line, partial) to = to, __index = h, hunk = h, + lines = hunk_lines, -- conflict = conflict, } diff --git a/lua/neogit/popups/revert/actions.lua b/lua/neogit/popups/revert/actions.lua index cc0004890..7d49c28ae 100644 --- a/lua/neogit/popups/revert/actions.lua +++ b/lua/neogit/popups/revert/actions.lua @@ -62,10 +62,6 @@ function M.changes(popup) end end -function M.hunk(popup) - git.revert.hunk(popup.state.env.item.hunk, popup:get_arguments()) -end - function M.continue() git.revert.continue() end diff --git a/lua/neogit/popups/revert/init.lua b/lua/neogit/popups/revert/init.lua index d5863165b..092f16596 100644 --- a/lua/neogit/popups/revert/init.lua +++ b/lua/neogit/popups/revert/init.lua @@ -23,7 +23,6 @@ function M.create(env) :group_heading("Revert") :action_if(not in_progress, "v", "Commit(s)", actions.commits) :action_if(not in_progress, "V", "Changes", actions.changes) - :action_if(((not in_progress) and env.item ~= nil), "h", "Hunk", actions.hunk) :action_if(in_progress, "v", "continue", actions.continue) :action_if(in_progress, "s", "skip", actions.skip) :action_if(in_progress, "a", "abort", actions.abort) diff --git a/tests/specs/neogit/lib/git/index_spec.lua b/tests/specs/neogit/lib/git/index_spec.lua index cc0358087..3d1be1cc6 100644 --- a/tests/specs/neogit/lib/git/index_spec.lua +++ b/tests/specs/neogit/lib/git/index_spec.lua @@ -10,15 +10,17 @@ local function run_with_hunk(hunk, from, to, reverse) local header_matches = vim.fn.matchlist(lines[1], "@@ -\\(\\d\\+\\),\\(\\d\\+\\) +\\(\\d\\+\\),\\(\\d\\+\\) @@") return generate_patch_from_selection({ + name = "test.txt", + absolute_path = "test.txt", + diff = { lines = lines }, + }, { first = 1, last = #lines, index_from = header_matches[2], index_len = header_matches[3], diff_from = diff_from, diff_to = #lines, - lines = vim.list_slice(lines, 2), - file = "test.txt", - }, { from = from, to = to, reverse = reverse }) + }, diff_from + from, diff_from + to, reverse) end describe("patch creation", function() diff --git a/tests/specs/neogit/lib/git/log_spec.lua b/tests/specs/neogit/lib/git/log_spec.lua index f3618c353..446eaa07e 100644 --- a/tests/specs/neogit/lib/git/log_spec.lua +++ b/tests/specs/neogit/lib/git/log_spec.lua @@ -96,7 +96,6 @@ describe("lib.git.log.parse", function() index_from = 692, index_len = 33, length = 40, - file = "lua/neogit/status.lua", line = "@@ -692,33 +692,28 @@ end", lines = { " ---@param first_line number", @@ -150,7 +149,6 @@ describe("lib.git.log.parse", function() index_from = 734, index_len = 14, length = 15, - file = "lua/neogit/status.lua", line = "@@ -734,14 +729,10 @@ function M.get_item_hunks(item, first_line, last_line, partial)", lines = { " setmetatable(o, o)", @@ -292,7 +290,6 @@ describe("lib.git.log.parse", function() index_len = 7, length = 9, line = "@@ -1,7 +1,9 @@", - file = "LICENSE", lines = { " MIT License", " ",