local M = {} local git = require('diffs.git') local dbg = require('diffs.log').dbg ---@param old_lines string[] ---@param new_lines string[] ---@param old_name string ---@param new_name string ---@return string[] local function generate_unified_diff(old_lines, new_lines, old_name, new_name) local old_content = table.concat(old_lines, '\n') local new_content = table.concat(new_lines, '\n') local diff_output = vim.diff(old_content, new_content, { result_type = 'unified', ctxlen = 3, }) if not diff_output or diff_output == '' then return {} end local diff_lines = vim.split(diff_output, '\n', { plain = true }) local result = { 'diff --git a/' .. old_name .. ' b/' .. new_name, '--- a/' .. old_name, '+++ b/' .. new_name, } for _, line in ipairs(diff_lines) do table.insert(result, line) end return result end ---@param revision? string function M.gdiff(revision) revision = revision or 'HEAD' local bufnr = vim.api.nvim_get_current_buf() local filepath = vim.api.nvim_buf_get_name(bufnr) if filepath == '' then vim.notify('diffs: buffer has no file', vim.log.levels.ERROR) return end local rel_path = git.get_relative_path(filepath) if not rel_path then vim.notify('diffs: not in a git repository', vim.log.levels.ERROR) return end local old_lines, err = git.get_file_content(revision, filepath) if not old_lines then vim.notify('diffs: ' .. (err or 'unknown error'), vim.log.levels.ERROR) return end local new_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) local diff_lines = generate_unified_diff(old_lines, new_lines, rel_path, rel_path) if #diff_lines == 0 then vim.notify('diffs: no changes', vim.log.levels.INFO) return end local diff_buf = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_lines(diff_buf, 0, -1, false, diff_lines) vim.api.nvim_set_option_value('buftype', 'nofile', { buf = diff_buf }) vim.api.nvim_set_option_value('bufhidden', 'wipe', { buf = diff_buf }) vim.api.nvim_set_option_value('modifiable', false, { buf = diff_buf }) vim.api.nvim_set_option_value('filetype', 'diff', { buf = diff_buf }) vim.api.nvim_buf_set_name(diff_buf, 'diffs://' .. revision .. ':' .. rel_path) vim.cmd('vsplit') vim.api.nvim_win_set_buf(0, diff_buf) dbg('opened diff buffer %d for %s against %s', diff_buf, rel_path, revision) vim.schedule(function() require('diffs').attach(diff_buf) end) end function M.setup() vim.api.nvim_create_user_command('Gdiff', function(opts) M.gdiff(opts.args ~= '' and opts.args or nil) end, { nargs = '?', desc = 'Show unified diff against git revision (default: HEAD)', }) end return M