Skip to content

Commit 1f3e985

Browse files
committed
feaT(git): binds for commits <-> diff <-> hunks
1 parent 6e41ba7 commit 1f3e985

3 files changed

Lines changed: 75 additions & 49 deletions

File tree

lua/fzf-lua/config.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,12 @@ function M.normalize_opts(opts, globals, __resume_key) ---@diagnostic disable
983983
opts.fn_preprocess = [[return require("fzf-lua.make_entry").preprocess]]
984984
end
985985

986+
-- set by git_{commits|diff|hunks} actions
987+
if opts["__pos_" .. utils.get_info().cmd] then
988+
opts.locate = opts.locate == nil and true or opts.locate
989+
opts.__locate_pos = opts.__locate_pos or opts["__pos_" .. utils.get_info().cmd]
990+
end
991+
986992
if opts.locate and utils.has(opts, "fzf", { 0, 36 }) then
987993
table.insert(opts._fzf_cli_args, "--bind=" .. libuv.shellescape("load:+transform:"
988994
.. FzfLua.shell.stringify_data(function(_, _, _)

lua/fzf-lua/defaults.lua

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -668,11 +668,8 @@ M.defaults.git = {
668668
---@class fzf-lua.config.GitDiff: fzf-lua.config.GitBase
669669
---Git reference(s) to compare against.
670670
---@field ref? string|string[]
671-
-- `compare_against` was renamed to `ref1`
672671
---Git reference used as the base for the comparison.
673672
---@field ref1? string
674-
---Fzf cursor start position for ctrl-q git_commits
675-
---@field _pos? number
676673
diff = {
677674
cmd = "git --no-pager diff --name-only {ref1} {ref}",
678675
ref = nil,
@@ -688,14 +685,22 @@ M.defaults.git = {
688685
_actions = function() return M.globals.actions.files end,
689686
_headers = { "cwd", "actions" },
690687
actions = {
688+
["ctrl-d"] = {
689+
fn = function(s, _o)
690+
if not s[1] then return FzfLua.utils.fzf_exit() end
691+
local o = vim.deepcopy(_o.__call_opts)
692+
o["__pos_" .. FzfLua.get_info().cmd] = tonumber(s[2])
693+
o.file = FzfLua.path.entry_to_file(s[1], _o).path
694+
FzfLua.git_hunks(o)
695+
end,
696+
header = "git hunks",
697+
exec_silent = true,
698+
field_index = "{} $FZF_POS",
699+
},
691700
["ctrl-q"] = {
692-
fn = function(_, _o)
701+
fn = function(s, _o)
693702
local o = vim.deepcopy(_o.__call_opts)
694-
if o._pos then
695-
o._fzf_cli_args = o._fzf_cli_args or {}
696-
table.insert(o._fzf_cli_args, "--bind="
697-
.. FzfLua.libuv.shellescape(string.format("load:+pos(%d)", o._pos)))
698-
end
703+
o["__pos_" .. FzfLua.get_info().cmd] = tonumber(s[2])
699704
FzfLua.git_commits(o)
700705
end,
701706
reuse = true,
@@ -705,12 +710,17 @@ M.defaults.git = {
705710
},
706711
---Git diff hunks (changed lines).
707712
---@class fzf-lua.config.GitHunks: fzf-lua.config.GitBase
708-
---Git reference to compare against.
709-
---@field ref? string
713+
---Git file to diff
714+
---@field file? string
715+
---Git reference(s) to compare against.
716+
---@field ref? string|string[]
717+
---Git reference used as the base for the comparison.
718+
---@field ref1? string
710719
hunks = {
711720
previewer = M._default_previewer_fn,
712-
cmd = "git --no-pager diff --color=always {ref}",
713-
ref = "HEAD",
721+
cmd = "git --no-pager diff --color=always {ref1} {ref} {file}",
722+
ref = nil,
723+
ref1 = nil,
714724
multiprocess = true, ---@type integer|boolean
715725
fn_transform = [[return require("fzf-lua.make_entry").git_hunk]],
716726
fn_preprocess = [[return require("fzf-lua.make_entry").preprocess]],
@@ -723,7 +733,14 @@ M.defaults.git = {
723733
},
724734
_fzf_nth_devicons = true,
725735
_actions = function() return M.globals.actions.files end,
726-
_headers = { "cwd" },
736+
_headers = { "cwd", "actions" },
737+
actions = {
738+
["ctrl-q"] = {
739+
fn = function(_, _o) FzfLua.git_diff(vim.deepcopy(_o.__call_opts)) end,
740+
reuse = true,
741+
header = "git diff"
742+
},
743+
},
727744
},
728745
---Git commits (project).
729746
---@class fzf-lua.config.GitCommits: fzf-lua.config.GitBase
@@ -741,7 +758,7 @@ M.defaults.git = {
741758
local o = vim.deepcopy(_o.__call_opts)
742759
o.ref = s[1]:match("[^ ]+")
743760
o.ref1 = o.ref .. "~"
744-
o._pos = tonumber(s[2])
761+
o["__pos_" .. FzfLua.get_info().cmd] = tonumber(s[2])
745762
FzfLua.git_diff(o)
746763
end,
747764
header = "git diff",

lua/fzf-lua/providers/git.lua

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,9 @@ local git_validate_ref = function(opts, ref)
104104
return true
105105
end
106106

107-
---@param opts fzf-lua.config.GitDiff|{}?
108-
---@return thread?, string?, table?
109-
M.diff = function(opts)
110-
---@type fzf-lua.config.GitDiff
111-
opts = config.normalize_opts(opts, "git.diff")
112-
if not opts then return end
107+
---@param opts fzf-lua.config.GitDiff|fzf-lua.config.GitHunks
108+
---@return table?
109+
local normalize_diff_opts = function(opts)
113110
-- Backward compat `compare_against` -> `ref1`
114111
---@diagnostic disable-next-line: undefined-field
115112
opts.ref1 = opts.compare_against or opts.ref1
@@ -137,15 +134,44 @@ M.diff = function(opts)
137134
end
138135
opts.cmd = opts.cmd:gsub("[<{]ref[}>]", opts.ref or "")
139136
opts.cmd = opts.cmd:gsub("[<{]ref1[}>]", opts.ref1 or "")
140-
opts.preview = opts.preview:gsub("[<{]ref[}>]", opts.ref or "")
141-
opts.preview = opts.preview:gsub("[<{]ref1[}>]", opts.ref1 or "")
142-
opts = set_git_cwd_args(opts)
143-
if not opts.cwd then return end
144-
opts.preview = git_preview(opts, "{-1}")
137+
opts.cmd = opts.cmd:gsub("[<{]file[}>]", opts.file and libuv.shellescape(opts.file) or "")
138+
if type(opts.preview) == "string" then
139+
opts.preview = opts.preview:gsub("[<{]ref[}>]", opts.ref or "")
140+
opts.preview = opts.preview:gsub("[<{]ref1[}>]", opts.ref1 or "")
141+
opts.preview = git_preview(opts, "{-1}")
142+
end
145143
if type(opts._headers) == "table" then
146144
table.insert(opts._headers, "ref")
147145
table.insert(opts._headers, "ref1")
148146
end
147+
return set_git_cwd_args(opts)
148+
end
149+
150+
---@param opts fzf-lua.config.GitDiff|{}?
151+
---@return thread?, string?, table?
152+
M.diff = function(opts)
153+
---@type fzf-lua.config.GitDiff
154+
opts = config.normalize_opts(opts, "git.diff")
155+
if not opts then return end
156+
opts = normalize_diff_opts(opts)
157+
if not opts or not opts.cwd then return end
158+
return core.fzf_exec(opts.cmd, opts)
159+
end
160+
161+
162+
---@param opts fzf-lua.config.GitHunks|{}?
163+
---@return thread?, string?, table?
164+
M.hunks = function(opts)
165+
---@type fzf-lua.config.GitHunks
166+
opts = config.normalize_opts(opts, "git.hunks")
167+
if not opts then return end
168+
opts = normalize_diff_opts(opts)
169+
if not opts or not opts.cwd then return end
170+
171+
-- we don't need git icons since we get them
172+
-- as part of our `git status -s`
173+
opts.git_icons = false
174+
149175
return core.fzf_exec(opts.cmd, opts)
150176
end
151177

@@ -317,27 +343,4 @@ M.stash = function(opts)
317343
return core.fzf_exec(opts.cmd, opts)
318344
end
319345

320-
---@param opts fzf-lua.config.GitHunks|{}?
321-
---@return thread?, string?, table?
322-
M.hunks = function(opts)
323-
---@type fzf-lua.config.GitHunks
324-
opts = config.normalize_opts(opts, "git.hunks")
325-
if not opts then return end
326-
if type(opts.ref) == "string" and #opts.ref > 0 and not git_validate_ref(opts, opts.ref) then
327-
return
328-
end
329-
opts.cmd = opts.cmd:gsub("[<{]ref[}>]", opts.ref or "")
330-
opts = set_git_cwd_args(opts)
331-
if not opts.cwd then return end
332-
333-
-- we don't need git icons since we get them
334-
-- as part of our `git status -s`
335-
opts.git_icons = false
336-
337-
opts.header_prefix = opts.header_prefix or "+ - "
338-
opts.header_separator = opts.header_separator or "|"
339-
340-
return core.fzf_exec(opts.cmd, opts)
341-
end
342-
343346
return M

0 commit comments

Comments
 (0)