Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(builtin.git_diff): new picker for diff hunks #3131

Closed
wants to merge 2 commits into from
Closed
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
6 changes: 6 additions & 0 deletions doc/telescope.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4046,6 +4046,12 @@ previewers.git_file_diff() *telescope.previewers.git_file_diff()*



previewers.git_hunk_diff() *telescope.previewers.git_hunk_diff()*
A previewer that shows the current diff hunk. Used in git_diff.




previewers.display_content() *telescope.previewers.display_content()*
A deprecated way of displaying content more easily. Was written at a time,
where the buffer_previewer interface wasn't present. Nowadays it's easier
Expand Down
106 changes: 106 additions & 0 deletions lua/telescope/builtin/__git.lua
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,112 @@ git.status = function(opts)
:find()
end

git.diff = function(opts)
if opts.is_bare then
utils.notify("builtin.git_diff", {
msg = "This operation must be run in a work tree",
level = "ERROR",
})
return
end
local args = { "diff" }
if opts.additional_args then
vim.list_extend(args, opts.additional_args)
end
local git_cmd = git_command(args, opts)
local output = vim.fn.systemlist(git_cmd)

local results = {}
local filename = nil
local linenumber = nil
local hunk_lines = {}

for _, line in ipairs(output) do
-- new file
if vim.startswith(line, 'diff') then
-- Start of a new hunk
if hunk_lines[1] ~= nil then
table.insert(results, { filename = filename, lnum = linenumber, raw_lines = hunk_lines })
end

local _, filepath_, _ = line:match('^diff (.*) a/(.*) b/(.*)$')

filename = filepath_
linenumber = nil

hunk_lines = {}
elseif vim.startswith(line, '@') then
if filename ~= nil and linenumber ~= nil and #hunk_lines > 0 then
table.insert(results, { filename = filename, lnum = linenumber, raw_lines = hunk_lines })
hunk_lines = {}
end
-- Hunk header
-- @example "@@ -157,20 +157,6 @@ some content"
local _, _, c, _ = string.match(line, '@@ %-(.*),(.*) %+(.*),(.*) @@')
linenumber = tonumber(c)
hunk_lines = {}
table.insert(hunk_lines, line)
else
table.insert(hunk_lines, line)
end
end
-- Add the last hunk to the table
if hunk_lines[1] ~= nil then
table.insert(results, { filename = filename, lnum = linenumber, raw_lines = hunk_lines })
end

local function get_diff_line_idx(lines)
for i, line in ipairs(lines) do
if vim.startswith(line, '-') or vim.startswith(line, '+') then
return i
end
end
return -1
end

-- lnum in diff hunks points a few lines off actually changed line
-- update results to point at changed lines to be precise
for _, v in ipairs(results) do
local diff_line_idx = get_diff_line_idx(v.raw_lines)
diff_line_idx = math.max(
-- first line is header, next one is already handled
diff_line_idx - 2,
0
)
v.lnum = v.lnum + diff_line_idx
end

pickers
.new({}, {
prompt_title = 'Git Diff',
finder = finders.new_table({
results = results,
entry_maker = function(entry)
entry.value = entry.filename
entry.ordinal = entry.filename .. ':' .. entry.lnum
entry.display = entry.filename .. ':' .. entry.lnum
return entry
end,
}),
previewer = previewers.git_hunk_diff.new(opts),
sorter = conf.file_sorter({}),
on_complete = {
function(self)
local lines = self.manager:num_results()
local prompt = action_state.get_current_line()
if lines == 0 and prompt == "" then
utils.notify("builtin.git_diff", {
msg = "No changes found",
level = "ERROR",
})
actions.close(self.prompt_bufnr)
end
end,
},
})
:find()
end

local try_worktrees = function(opts)
local worktrees = conf.git_worktrees

Expand Down
2 changes: 2 additions & 0 deletions lua/telescope/builtin/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ builtin.git_branches = require_on_exported_call("telescope.builtin.__git").branc
---@field expand_dir boolean: pass flag `-uall` to show files in untracked directories (default: true)
builtin.git_status = require_on_exported_call("telescope.builtin.__git").status

builtin.git_diff = require_on_exported_call("telescope.builtin.__git").diff

--- Lists stash items in current repository
--- - Default keymaps:
--- - `<cr>`: runs `git apply` for currently selected stash
Expand Down
15 changes: 15 additions & 0 deletions lua/telescope/previewers/buffer_previewer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,21 @@ previewers.git_branch_log = defaulter(function(opts)
}
end, {})

previewers.git_hunk_diff = defaulter(function()
return previewers.new_buffer_previewer {
title = "Git Diff Preview",
get_buffer_by_name = function(_, entry)
return entry.value
end,

define_preview = function(self, entry, _)
local lines = entry.raw_lines or { 'empty' }
vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, lines)
putils.regex_highlighter(self.state.bufnr, 'diff')
end,
}
end, {})

previewers.git_stash_diff = defaulter(function(opts)
return previewers.new_buffer_previewer {
title = "Git Stash Preview",
Expand Down
3 changes: 3 additions & 0 deletions lua/telescope/previewers/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,9 @@ previewers.git_commit_message = buffer_previewer.git_commit_message
--- The run command is `git --no-pager diff $FILE`
previewers.git_file_diff = buffer_previewer.git_file_diff

--- A previewer that shows the current diff hunk. Used in git_diff.<br>
previewers.git_hunk_diff = buffer_previewer.git_hunk_diff

previewers.ctags = buffer_previewer.ctags
previewers.builtin = buffer_previewer.builtin
previewers.help = buffer_previewer.help
Expand Down
Loading