Skip to content
Open
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
40 changes: 33 additions & 7 deletions doc/diffview.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1789,13 +1789,38 @@ hooks *diffview-config-hooks*
Callback Parameters: ~
{bufnr} (`integer`)
The buffer number of the new buffer.
{ctx} (`table`)
{ctx} (`table`) *diffview-diff-buf-ctx*
• {symbol} (string)
A symbol that identifies the window's position in
the layout. These symbols correspond with the
figures under |diffview-config-view.x.layout|.
• {layout_name} (string)
The name of the current layout.
• {rev} (table)
The revision the buffer shows:
• {type} (string)
`"LOCAL"` (the working tree), `"COMMIT"`,
`"STAGE"` (an index stage), or `"CUSTOM"`
(content outside any VCS).
• {commit} (string|nil)
The full object name, for `"COMMIT"`.
• {stage} (integer|nil)
The stage number, for `"STAGE"`: 0 for the
index, 1 for the common ancestor, 2 for ours
and 3 for theirs.
• {tracks_head} (boolean)
Whether the revision was resolved from HEAD
and follows it when HEAD moves.
• {path} (string)
The file path, relative to {toplevel}.
• {toplevel} (string)
The root of the repository. Outside a repository,
the directory {path} is relative to.
• {adapter} (string|nil)
The VCS adapter: `"git"`, `"hg"`, `"jj"` or `"p4"`.
It determines how {rev.commit} is interpreted.
`nil` outside a repository (e.g.
|:DiffviewDiffFiles|).

{diff_buf_win_enter} (`fun(bufnr: integer, winid: integer, ctx: table)`)
Emitted after a diff buffer is displayed in a window.
Expand All @@ -1812,12 +1837,7 @@ hooks *diffview-config-hooks*
The window id of window inside which the buffer was
displayed.
{ctx} (`table`)
• {symbol} (string)
A symbol that identifies the window's position in
the layout. These symbols correspond with the
figures under |diffview-config-view.x.layout|.
• {layout_name} (string)
The name of the current layout.
See |diffview-diff-buf-ctx|.

Examples: >lua
hooks = {
Expand Down Expand Up @@ -2501,6 +2521,9 @@ For information on how to use User autocommands, see |User|.
such that |:setlocal| will apply settings to the
relevant buffer / window.

The autocommand's `data` holds the fields of
|diffview-diff-buf-ctx| and `bufnr`.

`DiffviewDiffBufWinEnter`
Fires after a diff buffer is displayed in a window.

Expand All @@ -2509,6 +2532,9 @@ For information on how to use User autocommands, see |User|.
such that |:setlocal| will apply settings to the
relevant buffer / window.

The autocommand's `data` holds the fields of
|diffview-diff-buf-ctx|, `bufnr` and `winid`.

`DiffviewFilesStaged` Fires after files have been staged or unstaged from
within a DiffView (e.g. via the stage/unstage actions).

Expand Down
10 changes: 10 additions & 0 deletions lua/diffview/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -649,9 +649,19 @@ M.defaults = {
include_bare = false,
},

---@class DiffviewDiffBufCtx.Rev
---@field type "LOCAL"|"COMMIT"|"STAGE"|"CUSTOM" What the buffer holds: the working tree, a commit, an index stage, or content outside any VCS.
---@field commit? string Full object name of the commit, for `COMMIT`.
---@field stage? integer Index stage (0 index, 1 common ancestor, 2 ours, 3 theirs), for `STAGE`.
---@field tracks_head boolean The rev was resolved from HEAD and follows it when HEAD moves.

---@class DiffviewDiffBufCtx
---@field symbol string Layout-window symbol ("a"|"b"|"c"|"d").
---@field layout_name string Concrete layout, e.g. "diff2_horizontal".
---@field rev DiffviewDiffBufCtx.Rev The revision the buffer shows.
---@field path string File path relative to `toplevel`.
---@field toplevel string Root of the repository. Outside a repository, the directory `path` is relative to.
---@field adapter? "git"|"hg"|"jj"|"p4" VCS adapter, which determines how `rev.commit` is interpreted. Nil outside a repository (e.g. `:DiffviewDiffFiles`).

---@class DiffviewHooks
---@field view_opened? fun(view: View)
Expand Down
16 changes: 12 additions & 4 deletions lua/diffview/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,19 @@ function M.init()
DiffviewGlobal.emitter:on("view_post_layout", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewViewPostLayout", modeline = false })
end)
DiffviewGlobal.emitter:on("diff_buf_read", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewDiffBufRead", modeline = false })
DiffviewGlobal.emitter:on("diff_buf_read", function(_, bufnr, ctx)
api.nvim_exec_autocmds("User", {
pattern = "DiffviewDiffBufRead",
modeline = false,
data = vim.tbl_extend("force", ctx, { bufnr = bufnr }),
})
end)
DiffviewGlobal.emitter:on("diff_buf_win_enter", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewDiffBufWinEnter", modeline = false })
DiffviewGlobal.emitter:on("diff_buf_win_enter", function(_, bufnr, winid, ctx)
api.nvim_exec_autocmds("User", {
pattern = "DiffviewDiffBufWinEnter",
modeline = false,
data = vim.tbl_extend("force", ctx, { bufnr = bufnr, winid = winid }),
})
end)
DiffviewGlobal.emitter:on("selection_changed", function(_)
api.nvim_exec_autocmds("User", { pattern = "DiffviewSelectionChanged", modeline = false })
Expand Down
27 changes: 23 additions & 4 deletions lua/diffview/scene/window.lua
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,7 @@ Window.open_file = async.void(function(self)
self.emitter:emit("post_open")

api.nvim_win_call(self.id, function()
DiffviewGlobal.emitter:emit("diff_buf_win_enter", self.file.bufnr, self.id, {
symbol = self.file.symbol,
layout_name = self.parent.name,
})
DiffviewGlobal.emitter:emit("diff_buf_win_enter", self.file.bufnr, self.id, self:diff_buf_ctx())
end)
---@diagnostic enable: invisible
end)
Expand All @@ -299,6 +296,28 @@ function Window:show_winbar_info()
return false
end

---Describe the diff buffer shown in this window, for the `diff_buf_read` and
---`diff_buf_win_enter` hooks and their `User` autocmds.
---@return DiffviewDiffBufCtx
function Window:diff_buf_ctx()
local file = self.file
local rev = file.rev

return {
symbol = file.symbol,
layout_name = self.parent.name,
rev = {
type = RevType[rev.type],
commit = rev.commit,
stage = rev.stage,
tracks_head = rev.track_head,
},
path = file.path,
toplevel = file.adapter.ctx.toplevel,
adapter = file.adapter.config_key,
}
end

function Window:is_nulled()
return self:is_valid() and api.nvim_win_get_buf(self.id) == File.NULL_FILE.bufnr
end
Expand Down
31 changes: 31 additions & 0 deletions lua/diffview/tests/functional/window_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,37 @@ describe("diffview.scene.window", function()
end)
end)

describe("diff_buf_ctx", function()
it("describes the buffer's position, revision and repository", function()
local adapter = mock_adapter({ config_key = "git" })
local win = make_window(adapter, {
path = "lua/foo.lua",
symbol = "a",
rev = GitRev(RevType.COMMIT, "abc1234", true),
})
win.parent = { name = "diff2_horizontal" }

assert.same({
symbol = "a",
layout_name = "diff2_horizontal",
rev = { type = "COMMIT", commit = "abc1234", tracks_head = true },
path = "lua/foo.lua",
toplevel = adapter.ctx.toplevel,
adapter = "git",
}, win:diff_buf_ctx())
end)

it("reports the stage of an index revision", function()
local win = make_window(mock_adapter(), {
symbol = "b",
rev = GitRev(RevType.STAGE, 2),
})
win.parent = { name = "diff3_mixed" }

assert.same({ type = "STAGE", stage = 2, tracks_head = false }, win:diff_buf_ctx().rev)
end)
end)

describe("open_file view.foldlevel", function()
-- Regression (#121): `view.foldlevel` must be copied onto the window's
-- `foldlevel` option when the diff buffer is shown, even if the file's
Expand Down