Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lua/diffview/scene/views/diff/diff_view.lua
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,16 @@ local update_files_impl = debounce.debounce_trailing(
end

if replace_noop then
-- Preserve the user's cycled/set layout across the refresh:
-- `get_updated_files` always builds new entries with the config
-- default, so without this the layout silently resets to the
-- default whenever `force_entry_refresh_on_noop` fires (jj on
-- any LOCAL-touching range: every tab_enter, focus_gained, poll,
-- or explicit `R` refresh).
if new_file.layout.class ~= old_file.layout.class then
new_file:convert_layout(old_file.layout.class --[[@as Layout ]])
end

if self.panel.cur_file == old_file then
self.panel:set_cur_file(new_file)
end
Expand Down
83 changes: 83 additions & 0 deletions lua/diffview/tests/functional/diff_view_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,89 @@ describe("diffview.scene.views.diff.DiffView", function()
end)
)

-- Regression: on adapters whose `force_entry_refresh_on_noop` returns
-- true (jj on any LOCAL-touching range), the NOOP branch destroys the
-- old entry and installs a fresh one built by `get_updated_files` with
-- the config default layout. Without preserving the old entry's layout
-- class across the swap, any `cycle_layout` / `set_layout` choice was
-- silently reset by every refresh (tab_enter, FocusGained, poll, R).
-- Bug: dlyongemallo/diffview-plus.nvim#312.
it(
"preserves the entry's layout class when force_entry_refresh_on_noop replaces it",
test_utils.async_test(function()
local Diff2Hor = require("diffview.scene.layouts.diff_2_hor").Diff2Hor
local Diff2Ver = require("diffview.scene.layouts.diff_2_ver").Diff2Ver

local repo = make_repo()
local view

local ok, err = pcall(function()
local file_spec = {
working = {
{ path = "init.txt", status = "M", stats = { additions = 0, deletions = 0 } },
},
staged = {},
conflicting = {},
}

view = CDiffView({
git_root = repo,
left = Rev(RevType.COMMIT, run({ "git", "rev-parse", "HEAD" }, repo), true),
right = Rev(RevType.LOCAL),
files = file_spec,
update_files = function()
return file_spec
end,
get_file_data = function()
return {}
end,
})

view:open()
vim.wait(2000, function()
return view.initialized
end, 10)

local original = view.files.working[1]
assert.is_truthy(original)
assert.True(original.layout:instanceof(Diff2Hor))

-- Simulate `cycle_layout`: swap the entry's stored layout to a
-- non-default class.
original:convert_layout(Diff2Ver)
eq(Diff2Ver, original.layout.class)

-- Force the NOOP replace-entry branch, as jj does whenever the
-- range touches LOCAL.
view.adapter.force_entry_refresh_on_noop = function()
return true
end

local refresh_done = false
view:update_files(function()
refresh_done = true
end)
vim.wait(2000, function()
return refresh_done
end, 10)
assert.is_true(refresh_done)

local refreshed = view.files.working[1]
assert.is_truthy(refreshed)
-- The entry was recreated (that's the whole point of the branch),
-- but the user's chosen layout class must survive the swap.
assert.are_not.equal(original, refreshed)
eq(Diff2Ver, refreshed.layout.class)
end)

close_view(view)
cleanup_repo(repo)
if not ok then
error(err)
end
end)
)

-- Regression: the wrapped impl signature were changed from
-- (self, callback) to (self, opts, callback). Legacy callers using
-- update_files(callback) would otherwise dereference opts.force on a
Expand Down
Loading