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
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ FileHistoryPanel.update_entries = async.wrap(function(self, callback)
self.updating = true

local layout_opt = {
default_layout = self.parent:get_default_layout() --[[@as Diff2 ]],
default_layout = self.parent:get_default_layout(),
pin_local = self.parent.pin_local,
pinned_path = self.parent.pinned_path,
-- Closure into the view's pin_local cache: adapters call this when
Expand Down
8 changes: 4 additions & 4 deletions lua/diffview/scene/views/file_history/listeners.lua
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ return function(view)
local file = view:infer_cur_file()

if file then
local layout = file.layout --[[@as Diff2 ]]
local revs = file.revs

local new_view = DiffView({
adapter = view.adapter,
rev_arg = view.adapter:rev_to_pretty_string(layout.a.file.rev, layout.b.file.rev),
left = layout.a.file.rev,
right = layout.b.file.rev,
rev_arg = view.adapter:rev_to_pretty_string(revs.a, revs.b),
left = revs.a,
right = revs.b,
options = { selected_file = file.absolute_path },
})

Expand Down
80 changes: 80 additions & 0 deletions lua/diffview/tests/functional/actions_features_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,86 @@ describe("copy_hash honors vim.v.register (f728b1f)", function()
end)
end)

-----------------------------------------------------------------------
-- #231: file_history `open_in_diffview` derives revs from `file.revs`.
-- `file.revs` is the canonical rev pair on a FileEntry and is set for
-- every layout class, so the action works under any layout. Reaching
-- into the layout's window files only works for layouts that expose
-- `.a` and `.b` Windows (`Diff2`); single-window layouts (`diff1_*`)
-- have no `.a` window.
-----------------------------------------------------------------------

describe("file_history open_in_diffview is layout-agnostic (#231)", function()
local listeners_factory = require("diffview.scene.views.file_history.listeners")

it("uses file.revs without dereferencing file.layout", function()
-- Trap layout: errors on any field access so a regression that
-- indexes `file.layout.{a,b}.file.rev` (or any other field) is
-- caught at the moment of access.
local layout_trap = setmetatable({}, {
__index = function(_, key)
error("open_in_diffview must not index file.layout (got '" .. key .. "')")
end,
})

local rev_a, rev_b = "<rev_a>", "<rev_b>"
local file = {
revs = { a = rev_a, b = rev_b },
absolute_path = "/repo/foo.lua",
layout = layout_trap,
}

local captured = {}
local mock_view = {
adapter = {
rev_to_pretty_string = function(_, a, b)
captured.pretty_args = { a, b }
return "<pretty>"
end,
},
infer_cur_file = function()
return file
end,
}

-- Swap the modules the listener resolves lazily. `listeners.lua` holds
-- `lazy.access(...)` wrappers that resolve on first call via
-- `require()`, so replacing `package.loaded` here captures the swap.
-- The wrappers cache their resolved values, so the swap is only
-- effective if no earlier code path has already resolved them.
local diff_view_path = "diffview.scene.views.diff.diff_view"
local lib_path = "diffview.lib"
local orig_diff_view_mod = package.loaded[diff_view_path]
local orig_lib = package.loaded[lib_path]

package.loaded[diff_view_path] = {
DiffView = function(opts)
captured.opts = opts
return { open = function() end }
end,
}
package.loaded[lib_path] = setmetatable({
add_view = function(v)
captured.added = v
end,
}, { __index = orig_lib })

local listeners = listeners_factory(mock_view)
local ok, err = pcall(listeners.open_in_diffview)

package.loaded[diff_view_path] = orig_diff_view_mod
package.loaded[lib_path] = orig_lib

assert(ok, err)
eq({ rev_a, rev_b }, captured.pretty_args)
eq(rev_a, captured.opts.left)
eq(rev_b, captured.opts.right)
eq("<pretty>", captured.opts.rev_arg)
eq("/repo/foo.lua", captured.opts.options.selected_file)
assert.is_not_nil(captured.added)
end)
end)

-----------------------------------------------------------------------
-- 431ee89: prevent scrollbind/cursorbind from persisting after close.
-- The NULL_FILE winopts explicitly set scrollbind=false and
Expand Down
Loading