mirror of
https://github.com/lewis6991/gitsigns.nvim
synced 2025-02-23 16:26:52 +00:00
Refactor diff code
- Simplify external diff code and make it's api consistent with FFI diff. - Move diff code into separate modules diff_ext and diff_ffi.
This commit is contained in:
parent
b685aa405f
commit
0180dfd7ae
@ -593,6 +593,7 @@ word_diff *gitsigns-config-word_diff*
|
||||
Type: `boolean`, Default: `false`
|
||||
|
||||
Highlight intra-line word differences in the buffer.
|
||||
Requires `config.use_internal_diff = true` .
|
||||
|
||||
Uses the highlights:
|
||||
• GitSignsAddLn
|
||||
|
2
lua/gitsigns.lua
generated
2
lua/gitsigns.lua
generated
@ -408,7 +408,7 @@ M.setup = void(function(cfg)
|
||||
manager.apply_win_signs(bufnr, bcache.pending_signs, top + 1, bot + 1)
|
||||
|
||||
|
||||
return config.word_diff
|
||||
return config.word_diff and config.use_internal_diff
|
||||
end,
|
||||
on_line = function(_, _, bufnr, row)
|
||||
manager.apply_word_diff(bufnr, row)
|
||||
|
18
lua/gitsigns/actions.lua
generated
18
lua/gitsigns/actions.lua
generated
@ -352,14 +352,16 @@ M.preview_hunk = function()
|
||||
api.nvim_buf_set_var(cbuf, '_gitsigns_preview_open', true)
|
||||
vim.cmd([[autocmd CursorMoved,CursorMovedI <buffer> ++once silent! unlet b:_gitsigns_preview_open]])
|
||||
|
||||
local regions = require('gitsigns.diff').run_word_diff(hunk.lines)
|
||||
local offset = #lines - #hunk.lines
|
||||
for _, region in ipairs(regions) do
|
||||
local line, scol, ecol = region[1], region[3], region[4]
|
||||
api.nvim_buf_set_extmark(bufnr, ns, line + offset - 1, scol, {
|
||||
end_col = ecol,
|
||||
hl_group = 'TermCursor',
|
||||
})
|
||||
if config.use_internal_diff then
|
||||
local regions = require('gitsigns.diff_ffi').run_word_diff(hunk.lines)
|
||||
local offset = #lines - #hunk.lines
|
||||
for _, region in ipairs(regions) do
|
||||
local line, scol, ecol = region[1], region[3], region[4]
|
||||
api.nvim_buf_set_extmark(bufnr, ns, line + offset - 1, scol, {
|
||||
end_col = ecol,
|
||||
hl_group = 'TermCursor',
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
82
lua/gitsigns/diff_ext.lua
generated
Normal file
82
lua/gitsigns/diff_ext.lua
generated
Normal file
@ -0,0 +1,82 @@
|
||||
local git = require('gitsigns.git')
|
||||
|
||||
local gs_hunks = require("gitsigns.hunks")
|
||||
local Hunk = gs_hunks.Hunk
|
||||
local util = require('gitsigns.util')
|
||||
local a = require('plenary.async')
|
||||
|
||||
local M = {}
|
||||
|
||||
|
||||
|
||||
|
||||
local function write_to_file(path, text)
|
||||
local f, err = io.open(path, 'wb')
|
||||
if f == nil then
|
||||
error(err)
|
||||
end
|
||||
for _, l in ipairs(text) do
|
||||
f:write(l)
|
||||
f:write('\n')
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
|
||||
M.run_diff = function(
|
||||
text_cmp,
|
||||
text_buf,
|
||||
diff_algo)
|
||||
|
||||
local results = {}
|
||||
|
||||
if not util.is_unix then
|
||||
|
||||
a.util.scheduler()
|
||||
end
|
||||
|
||||
local file_buf = util.tmpname() .. '_buf'
|
||||
local file_cmp = util.tmpname() .. '_cmp'
|
||||
|
||||
write_to_file(file_buf, text_buf)
|
||||
write_to_file(file_cmp, text_cmp)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
git.command({
|
||||
'-c', 'core.safecrlf=false',
|
||||
'diff',
|
||||
'--color=never',
|
||||
'--diff-algorithm=' .. diff_algo,
|
||||
'--patch-with-raw',
|
||||
'--unified=0',
|
||||
file_cmp,
|
||||
file_buf,
|
||||
}, {
|
||||
on_stdout = function(_, line)
|
||||
if vim.startswith(line, '@@') then
|
||||
table.insert(results, gs_hunks.parse_diff_line(line))
|
||||
elseif #results > 0 then
|
||||
table.insert(results[#results].lines, line)
|
||||
end
|
||||
end,
|
||||
})
|
||||
os.remove(file_buf)
|
||||
os.remove(file_cmp)
|
||||
return results
|
||||
end
|
||||
|
||||
return M
|
245
lua/gitsigns/diff_ffi.lua
generated
Normal file
245
lua/gitsigns/diff_ffi.lua
generated
Normal file
@ -0,0 +1,245 @@
|
||||
local create_hunk = require("gitsigns.hunks").create_hunk
|
||||
local Hunk = require('gitsigns.hunks').Hunk
|
||||
|
||||
local ffi = require("ffi")
|
||||
|
||||
ffi.cdef([[
|
||||
typedef struct s_mmbuffer { const char *ptr; long size; } mmbuffer_t;
|
||||
|
||||
typedef struct s_xpparam {
|
||||
unsigned long flags;
|
||||
|
||||
// See Documentation/diff-options.txt.
|
||||
char **anchors;
|
||||
size_t anchors_nr;
|
||||
} xpparam_t;
|
||||
|
||||
typedef long (__stdcall *find_func_t)(
|
||||
const char *line,
|
||||
long line_len,
|
||||
char *buffer,
|
||||
long buffer_size,
|
||||
void *priv
|
||||
);
|
||||
|
||||
typedef int (__stdcall *xdl_emit_hunk_consume_func_t)(
|
||||
long start_a, long count_a, long start_b, long count_b,
|
||||
void *cb_data
|
||||
);
|
||||
|
||||
typedef struct s_xdemitconf {
|
||||
long ctxlen;
|
||||
long interhunkctxlen;
|
||||
unsigned long flags;
|
||||
find_func_t find_func;
|
||||
void *find_func_priv;
|
||||
xdl_emit_hunk_consume_func_t hunk_func;
|
||||
} xdemitconf_t;
|
||||
|
||||
typedef struct s_xdemitcb {
|
||||
void *priv;
|
||||
int (__stdcall *outf)(void *, mmbuffer_t *, int);
|
||||
} xdemitcb_t;
|
||||
|
||||
int xdl_diff(
|
||||
mmbuffer_t *mf1,
|
||||
mmbuffer_t *mf2,
|
||||
xpparam_t const *xpp,
|
||||
xdemitconf_t const *xecfg,
|
||||
xdemitcb_t *ecb
|
||||
);
|
||||
]])
|
||||
|
||||
local MMBuffer = {}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local function setup_mmbuffer(lines)
|
||||
local text = vim.tbl_isempty(lines) and '' or table.concat(lines, '\n') .. '\n'
|
||||
return text, #text
|
||||
end
|
||||
|
||||
local XPParam = {}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local function get_xpparam_flag(diff_algo)
|
||||
local daflag = 0
|
||||
|
||||
if diff_algo == 'minimal' then daflag = 1
|
||||
elseif diff_algo == 'patience' then daflag = math.floor(2 ^ 14)
|
||||
elseif diff_algo == 'histogram' then daflag = math.floor(2 ^ 15)
|
||||
end
|
||||
|
||||
return daflag
|
||||
end
|
||||
|
||||
local Long = {}
|
||||
|
||||
|
||||
|
||||
local XDEmitConf = {}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local M = {}
|
||||
|
||||
local DiffResult = {}
|
||||
|
||||
local mmba = ffi.new('mmbuffer_t')
|
||||
local mmbb = ffi.new('mmbuffer_t')
|
||||
local xpparam = ffi.new('xpparam_t')
|
||||
local emitcb = ffi.new('xdemitcb_t')
|
||||
|
||||
local function run_diff_xdl(fa, fb, diff_algo)
|
||||
mmba.ptr, mmba.size = setup_mmbuffer(fa)
|
||||
mmbb.ptr, mmbb.size = setup_mmbuffer(fb)
|
||||
xpparam.flags = get_xpparam_flag(diff_algo)
|
||||
|
||||
local results = {}
|
||||
|
||||
local hunk_func = ffi.cast('xdl_emit_hunk_consume_func_t', function(
|
||||
start_a, count_a, start_b, count_b)
|
||||
|
||||
local ca = tonumber(count_a)
|
||||
local cb = tonumber(count_b)
|
||||
local sa = tonumber(start_a)
|
||||
local sb = tonumber(start_b)
|
||||
|
||||
|
||||
|
||||
if ca > 0 then sa = sa + 1 end
|
||||
if cb > 0 then sb = sb + 1 end
|
||||
|
||||
results[#results + 1] = { sa, ca, sb, cb }
|
||||
return 0
|
||||
end)
|
||||
|
||||
local emitconf = ffi.new('xdemitconf_t')
|
||||
emitconf.hunk_func = hunk_func
|
||||
|
||||
local ok = ffi.C.xdl_diff(mmba, mmbb, xpparam, emitconf, emitcb)
|
||||
|
||||
hunk_func:free()
|
||||
|
||||
return ok == 0 and results
|
||||
end
|
||||
|
||||
jit.off(run_diff_xdl)
|
||||
|
||||
function M.run_diff(fa, fb, diff_algo)
|
||||
local results = run_diff_xdl(fa, fb, diff_algo)
|
||||
|
||||
local hunks = {}
|
||||
|
||||
for _, r in ipairs(results) do
|
||||
local rs, rc, as, ac = unpack(r)
|
||||
local hunk = create_hunk(rs, rc, as, ac)
|
||||
hunk.head = ('@@ -%d%s +%d%s @@'):format(
|
||||
rs, rc > 0 and ',' .. rc or '',
|
||||
as, ac > 0 and ',' .. ac or '')
|
||||
|
||||
if rc > 0 then
|
||||
for i = rs, rs + rc - 1 do
|
||||
table.insert(hunk.lines, '-' .. (fa[i] or ''))
|
||||
end
|
||||
end
|
||||
if ac > 0 then
|
||||
for i = as, as + ac - 1 do
|
||||
table.insert(hunk.lines, '+' .. (fb[i] or ''))
|
||||
end
|
||||
end
|
||||
table.insert(hunks, hunk)
|
||||
end
|
||||
|
||||
return hunks
|
||||
end
|
||||
|
||||
local Region = {}
|
||||
|
||||
local gaps_between_regions = 5
|
||||
|
||||
function M.run_word_diff(hunk_body)
|
||||
local removed, added = 0, 0
|
||||
for _, line in ipairs(hunk_body) do
|
||||
if line:sub(1, 1) == '-' then
|
||||
removed = removed + 1
|
||||
elseif line:sub(1, 1) == '+' then
|
||||
added = added + 1
|
||||
end
|
||||
end
|
||||
|
||||
if removed ~= added then
|
||||
return {}
|
||||
end
|
||||
|
||||
local ret = {}
|
||||
|
||||
for i = 1, removed do
|
||||
|
||||
local rline = hunk_body[i]:sub(2)
|
||||
local aline = hunk_body[i + removed]:sub(2)
|
||||
|
||||
local a, b = vim.split(rline, ''), vim.split(aline, '')
|
||||
|
||||
local hunks0 = {}
|
||||
for _, r in ipairs(run_diff_xdl(a, b)) do
|
||||
local rs, rc, as, ac = unpack(r)
|
||||
|
||||
|
||||
if rc == 0 then rs = rs + 1 end
|
||||
if ac == 0 then as = as + 1 end
|
||||
|
||||
|
||||
hunks0[#hunks0 + 1] = create_hunk(rs, rc, as, ac)
|
||||
end
|
||||
|
||||
|
||||
local hunks = { hunks0[1] }
|
||||
for i = 2, #hunks0 do
|
||||
local h, n = hunks[#hunks], hunks0[i]
|
||||
if not h or not n then break end
|
||||
if n.added.start - h.added.start - h.added.count < gaps_between_regions then
|
||||
h.added.count = n.added.start + n.added.count - h.added.start
|
||||
h.removed.count = n.removed.start + n.removed.count - h.removed.start
|
||||
|
||||
if h.added.count > 0 or h.removed.count > 0 then
|
||||
h.type = 'change'
|
||||
end
|
||||
else
|
||||
hunks[#hunks + 1] = n
|
||||
end
|
||||
end
|
||||
|
||||
for _, h in ipairs(hunks) do
|
||||
local rem = { i, h.type, h.removed.start, h.removed.start + h.removed.count }
|
||||
local add = { i + removed, h.type, h.added.start, h.added.start + h.added.count }
|
||||
|
||||
ret[#ret + 1] = rem
|
||||
ret[#ret + 1] = add
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
return M
|
96
lua/gitsigns/git.lua
generated
96
lua/gitsigns/git.lua
generated
@ -82,7 +82,6 @@ local M = {BlameInfo = {}, Version = {}, Obj = {}, }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local Obj = M.Obj
|
||||
@ -117,7 +116,7 @@ local function check_version(version)
|
||||
return true
|
||||
end
|
||||
|
||||
local command = a.wrap(function(args, spec, callback)
|
||||
M.command = a.wrap(function(args, spec, callback)
|
||||
local result = {}
|
||||
local reserr
|
||||
spec = spec or {}
|
||||
@ -176,7 +175,7 @@ local get_repo_info = function(path, cmd)
|
||||
|
||||
a.util.scheduler()
|
||||
|
||||
local results = command({
|
||||
local results = M.command({
|
||||
'rev-parse', '--show-toplevel', git_dir_opt, '--abbrev-ref', 'HEAD',
|
||||
}, {
|
||||
command = cmd or 'git',
|
||||
@ -193,77 +192,12 @@ local get_repo_info = function(path, cmd)
|
||||
return toplevel, gitdir, abbrev_head
|
||||
end
|
||||
|
||||
local function write_to_file(path, text)
|
||||
local f, err = io.open(path, 'wb')
|
||||
if f == nil then
|
||||
error(err)
|
||||
end
|
||||
for _, l in ipairs(text) do
|
||||
f:write(l)
|
||||
f:write('\n')
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
|
||||
M.run_diff = function(
|
||||
staged,
|
||||
text,
|
||||
diff_algo)
|
||||
|
||||
local results = {}
|
||||
|
||||
if not util.is_unix then
|
||||
|
||||
a.util.scheduler()
|
||||
end
|
||||
|
||||
local buffile = util.tmpname() .. '_buf'
|
||||
write_to_file(buffile, text)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
command({
|
||||
'-c', 'core.safecrlf=false',
|
||||
'diff',
|
||||
'--color=never',
|
||||
'--diff-algorithm=' .. diff_algo,
|
||||
'--patch-with-raw',
|
||||
'--unified=0',
|
||||
staged,
|
||||
buffile,
|
||||
}, {
|
||||
on_stdout = function(_, line)
|
||||
if startswith(line, '@@') then
|
||||
table.insert(results, gs_hunks.parse_diff_line(line))
|
||||
elseif #results > 0 then
|
||||
table.insert(results[#results].lines, line)
|
||||
end
|
||||
end,
|
||||
})
|
||||
os.remove(buffile)
|
||||
return results
|
||||
end
|
||||
|
||||
M.set_version = function(version)
|
||||
if version ~= 'auto' then
|
||||
M.version = parse_version(version)
|
||||
return
|
||||
end
|
||||
local results = command({ '--version' })
|
||||
local results = M.command({ '--version' })
|
||||
local line = results[1]
|
||||
assert(startswith(line, 'git version'), 'Unexpected output: ' .. line)
|
||||
local parts = vim.split(line, '%s+')
|
||||
@ -278,7 +212,7 @@ end
|
||||
Obj.command = function(self, args, spec)
|
||||
spec = spec or {}
|
||||
spec.cwd = self.toplevel
|
||||
return command({ '--git-dir=' .. self.gitdir, unpack(args) }, spec)
|
||||
return M.command({ '--git-dir=' .. self.gitdir, unpack(args) }, spec)
|
||||
end
|
||||
|
||||
Obj.update_abbrev_head = function(self)
|
||||
@ -336,24 +270,6 @@ Obj.get_show_text = function(self, object)
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
Obj.get_show = function(self, object, output_file)
|
||||
|
||||
|
||||
local outf, err = io.open(output_file, 'wb')
|
||||
if outf == nil then
|
||||
error(err)
|
||||
end
|
||||
self:command({ 'show', object }, {
|
||||
supress_stderr = true,
|
||||
on_stdout = function(_, line)
|
||||
outf:write(line)
|
||||
outf:write('\n')
|
||||
end,
|
||||
})
|
||||
outf:close()
|
||||
end
|
||||
|
||||
Obj.run_blame = function(self, lines, lnum)
|
||||
local results = self:command({
|
||||
'blame',
|
||||
@ -431,14 +347,14 @@ Obj.new = function(file)
|
||||
local self = setmetatable({}, { __index = Obj })
|
||||
|
||||
self.file = file
|
||||
self.username = command({ 'config', 'user.name' })[1]
|
||||
self.username = M.command({ 'config', 'user.name' })[1]
|
||||
self.toplevel, self.gitdir, self.abbrev_head =
|
||||
get_repo_info(util.dirname(file))
|
||||
|
||||
|
||||
if M.enable_yadm and not self.gitdir then
|
||||
if vim.startswith(file, os.getenv('HOME')) and
|
||||
#command({ 'ls-files', file }, { command = 'yadm' }) ~= 0 then
|
||||
#M.command({ 'ls-files', file }, { command = 'yadm' }) ~= 0 then
|
||||
self.toplevel, self.gitdir, self.abbrev_head =
|
||||
get_repo_info(util.dirname(file), 'yadm')
|
||||
end
|
||||
|
25
lua/gitsigns/manager.lua
generated
25
lua/gitsigns/manager.lua
generated
@ -17,8 +17,10 @@ local gs_debug = require("gitsigns.debug")
|
||||
local dprint = gs_debug.dprint
|
||||
local eprint = gs_debug.eprint
|
||||
local util = require('gitsigns.util')
|
||||
local git = require('gitsigns.git')
|
||||
|
||||
local gs_hunks = require("gitsigns.hunks")
|
||||
local Hunk = gs_hunks.Hunk
|
||||
|
||||
local setup_highlight = require('gitsigns.highlight').setup_highlight
|
||||
|
||||
local config = require('gitsigns.config').config
|
||||
@ -148,7 +150,7 @@ M.apply_word_diff = function(bufnr, row)
|
||||
for _, hunk in ipairs(cache[bufnr].hunks) do
|
||||
if lnum >= hunk.start and lnum <= hunk.vend then
|
||||
local size = #hunk.lines / 2
|
||||
local regions = require('gitsigns.diff').run_word_diff(hunk.lines)
|
||||
local regions = require('gitsigns.diff_ffi').run_word_diff(hunk.lines)
|
||||
for _, region in ipairs(regions) do
|
||||
local line = region[1]
|
||||
if lnum == hunk.start + line - size - 1 and
|
||||
@ -192,16 +194,17 @@ local update0 = function(bufnr, bcache)
|
||||
|
||||
local compare_object = bcache.get_compare_obj(bcache)
|
||||
|
||||
if config.use_internal_diff then
|
||||
local diff = require('gitsigns.diff')
|
||||
if not bcache.compare_text or config._refresh_staged_on_update then
|
||||
bcache.compare_text = git_obj:get_show_text(compare_object)
|
||||
end
|
||||
bcache.hunks = diff.run_diff(bcache.compare_text, buftext, config.diff_algorithm)
|
||||
else
|
||||
git_obj:get_show(compare_object, bcache.compare_file)
|
||||
bcache.hunks = git.run_diff(bcache.compare_file, buftext, config.diff_algorithm)
|
||||
if not bcache.compare_text or config._refresh_staged_on_update then
|
||||
bcache.compare_text = git_obj:get_show_text(compare_object)
|
||||
end
|
||||
|
||||
local run_diff
|
||||
if config.use_internal_diff then
|
||||
run_diff = require('gitsigns.diff_ffi').run_diff
|
||||
else
|
||||
run_diff = require('gitsigns.diff_ext').run_diff
|
||||
end
|
||||
bcache.hunks = run_diff(bcache.compare_text, buftext, config.diff_algorithm)
|
||||
bcache.pending_signs = gs_hunks.process_hunks(bcache.hunks)
|
||||
|
||||
scheduler()
|
||||
|
@ -408,7 +408,7 @@ M.setup = void(function(cfg: Config)
|
||||
manager.apply_win_signs(bufnr, bcache.pending_signs, top+1, bot+1)
|
||||
|
||||
-- Returning false prevents the on_line callbacks
|
||||
return config.word_diff
|
||||
return config.word_diff and config.use_internal_diff
|
||||
end,
|
||||
on_line = function(_, _, bufnr: integer, row: integer)
|
||||
manager.apply_word_diff(bufnr, row)
|
||||
|
@ -352,14 +352,16 @@ M.preview_hunk = function()
|
||||
api.nvim_buf_set_var(cbuf, '_gitsigns_preview_open', true)
|
||||
vim.cmd[[autocmd CursorMoved,CursorMovedI <buffer> ++once silent! unlet b:_gitsigns_preview_open]]
|
||||
|
||||
local regions = require('gitsigns.diff').run_word_diff(hunk.lines)
|
||||
local offset = #lines - #hunk.lines
|
||||
for _, region in ipairs(regions) do
|
||||
local line, scol, ecol = region[1], region[3], region[4]
|
||||
api.nvim_buf_set_extmark(bufnr as integer, ns, line + offset - 1, scol, {
|
||||
end_col = ecol,
|
||||
hl_group = 'TermCursor'
|
||||
})
|
||||
if config.use_internal_diff then
|
||||
local regions = require('gitsigns.diff_ffi').run_word_diff(hunk.lines)
|
||||
local offset = #lines - #hunk.lines
|
||||
for _, region in ipairs(regions) do
|
||||
local line, scol, ecol = region[1], region[3], region[4]
|
||||
api.nvim_buf_set_extmark(bufnr as integer, ns, line + offset - 1, scol, {
|
||||
end_col = ecol,
|
||||
hl_group = 'TermCursor'
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
82
teal/gitsigns/diff_ext.tl
Normal file
82
teal/gitsigns/diff_ext.tl
Normal file
@ -0,0 +1,82 @@
|
||||
local git = require('gitsigns.git')
|
||||
|
||||
local gs_hunks = require("gitsigns.hunks")
|
||||
local Hunk = gs_hunks.Hunk
|
||||
local util = require('gitsigns.util')
|
||||
local a = require('plenary.async')
|
||||
|
||||
local record M
|
||||
-- Async function
|
||||
run_diff: function({string}, {string}, string): {Hunk}
|
||||
end
|
||||
|
||||
local function write_to_file(path: string, text: {string})
|
||||
local f, err = io.open(path, 'wb')
|
||||
if f == nil then
|
||||
error(err)
|
||||
end
|
||||
for _, l in ipairs(text) do
|
||||
f:write(l)
|
||||
f:write('\n')
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
|
||||
M.run_diff = function(
|
||||
text_cmp: {string},
|
||||
text_buf: {string},
|
||||
diff_algo: string
|
||||
): {Hunk}
|
||||
local results: {Hunk} = {}
|
||||
|
||||
if not util.is_unix then
|
||||
-- tmpname must not be called in a callback on windows
|
||||
a.util.scheduler()
|
||||
end
|
||||
|
||||
local file_buf = util.tmpname()..'_buf'
|
||||
local file_cmp = util.tmpname()..'_cmp'
|
||||
|
||||
write_to_file(file_buf, text_buf)
|
||||
write_to_file(file_cmp, text_cmp)
|
||||
|
||||
-- Taken from gitgutter, diff.vim:
|
||||
--
|
||||
-- If a file has CRLF line endings and git's core.autocrlf is true, the file
|
||||
-- in git's object store will have LF line endings. Writing it out via
|
||||
-- git-show will produce a file with LF line endings.
|
||||
--
|
||||
-- If this last file is one of the files passed to git-diff, git-diff will
|
||||
-- convert its line endings to CRLF before diffing -- which is what we want
|
||||
-- but also by default outputs a warning on stderr.
|
||||
--
|
||||
-- warning: LF will be replace by CRLF in <temp file>.
|
||||
-- The file will have its original line endings in your working directory.
|
||||
--
|
||||
-- We can safely ignore the warning, we turn it off by passing the '-c
|
||||
-- "core.safecrlf=false"' argument to git-diff.
|
||||
|
||||
git.command({
|
||||
'-c', 'core.safecrlf=false',
|
||||
'diff',
|
||||
'--color=never',
|
||||
'--diff-algorithm='..diff_algo,
|
||||
'--patch-with-raw',
|
||||
'--unified=0',
|
||||
file_cmp,
|
||||
file_buf,
|
||||
}, {
|
||||
on_stdout = function(_, line: string)
|
||||
if vim.startswith(line, '@@') then
|
||||
table.insert(results, gs_hunks.parse_diff_line(line))
|
||||
elseif #results > 0 then
|
||||
table.insert(results[#results].lines, line)
|
||||
end
|
||||
end
|
||||
})
|
||||
os.remove(file_buf)
|
||||
os.remove(file_cmp)
|
||||
return results
|
||||
end
|
||||
|
||||
return M
|
@ -55,7 +55,7 @@ local record M
|
||||
enable_yadm: boolean
|
||||
|
||||
set_version: function(string)
|
||||
run_diff : function(string, {string}, string): {Hunk}
|
||||
command : function(args: {string}, spec: GJobSpec): {string}, string
|
||||
|
||||
record Obj
|
||||
toplevel : string
|
||||
@ -73,7 +73,6 @@ local record M
|
||||
update_abbrev_head : function(Obj)
|
||||
update_file_info : function(Obj): boolean
|
||||
unstage_file : function(Obj, string, string)
|
||||
get_show : function(Obj, string, string)
|
||||
get_show_text : function(Obj, string): {string}, string
|
||||
run_blame : function(Obj, {string}, number): M.BlameInfo
|
||||
file_info : function(Obj, string): string, string, string, boolean
|
||||
@ -117,7 +116,7 @@ local function check_version(version: {number,number,number}): boolean
|
||||
return true
|
||||
end
|
||||
|
||||
local command = a.wrap(function(args: {string}, spec: GJobSpec, callback: function({string}, string))
|
||||
M.command = a.wrap(function(args: {string}, spec: GJobSpec, callback: function({string}, string))
|
||||
local result: {string} = {}
|
||||
local reserr: string
|
||||
spec = spec or {}
|
||||
@ -176,7 +175,7 @@ local get_repo_info = function(path: string, cmd: string): string,string,string
|
||||
-- https://github.com/lewis6991/gitsigns.nvim/pull/215
|
||||
a.util.scheduler()
|
||||
|
||||
local results = command({
|
||||
local results = M.command({
|
||||
'rev-parse', '--show-toplevel', git_dir_opt, '--abbrev-ref', 'HEAD',
|
||||
}, {
|
||||
command = cmd or 'git',
|
||||
@ -193,77 +192,12 @@ local get_repo_info = function(path: string, cmd: string): string,string,string
|
||||
return toplevel, gitdir, abbrev_head
|
||||
end
|
||||
|
||||
local function write_to_file(path: string, text: {string})
|
||||
local f, err = io.open(path, 'wb')
|
||||
if f == nil then
|
||||
error(err)
|
||||
end
|
||||
for _, l in ipairs(text) do
|
||||
f:write(l)
|
||||
f:write('\n')
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
|
||||
M.run_diff = function(
|
||||
staged: string,
|
||||
text: {string},
|
||||
diff_algo: string
|
||||
): {Hunk}
|
||||
local results: {Hunk} = {}
|
||||
|
||||
if not util.is_unix then
|
||||
-- tmpname must not be called in a callback on windows
|
||||
a.util.scheduler()
|
||||
end
|
||||
|
||||
local buffile = util.tmpname()..'_buf'
|
||||
write_to_file(buffile, text)
|
||||
|
||||
-- Taken from gitgutter, diff.vim:
|
||||
--
|
||||
-- If a file has CRLF line endings and git's core.autocrlf is true, the file
|
||||
-- in git's object store will have LF line endings. Writing it out via
|
||||
-- git-show will produce a file with LF line endings.
|
||||
--
|
||||
-- If this last file is one of the files passed to git-diff, git-diff will
|
||||
-- convert its line endings to CRLF before diffing -- which is what we want
|
||||
-- but also by default outputs a warning on stderr.
|
||||
--
|
||||
-- warning: LF will be replace by CRLF in <temp file>.
|
||||
-- The file will have its original line endings in your working directory.
|
||||
--
|
||||
-- We can safely ignore the warning, we turn it off by passing the '-c
|
||||
-- "core.safecrlf=false"' argument to git-diff.
|
||||
|
||||
command({
|
||||
'-c', 'core.safecrlf=false',
|
||||
'diff',
|
||||
'--color=never',
|
||||
'--diff-algorithm='..diff_algo,
|
||||
'--patch-with-raw',
|
||||
'--unified=0',
|
||||
staged,
|
||||
buffile,
|
||||
}, {
|
||||
on_stdout = function(_, line: string)
|
||||
if startswith(line, '@@') then
|
||||
table.insert(results, gs_hunks.parse_diff_line(line))
|
||||
elseif #results > 0 then
|
||||
table.insert(results[#results].lines, line)
|
||||
end
|
||||
end
|
||||
})
|
||||
os.remove(buffile)
|
||||
return results
|
||||
end
|
||||
|
||||
M.set_version = function(version: string)
|
||||
if version ~= 'auto' then
|
||||
M.version = parse_version(version)
|
||||
return
|
||||
end
|
||||
local results = command{'--version'}
|
||||
local results = M.command{'--version'}
|
||||
local line = results[1]
|
||||
assert(startswith(line, 'git version'), 'Unexpected output: '..line)
|
||||
local parts = vim.split(line, '%s+')
|
||||
@ -278,7 +212,7 @@ end
|
||||
Obj.command = function(self: Obj, args: {string}, spec: GJobSpec): {string}, string
|
||||
spec = spec or {}
|
||||
spec.cwd = self.toplevel
|
||||
return command({'--git-dir='..self.gitdir, unpack(args)}, spec)
|
||||
return M.command({'--git-dir='..self.gitdir, unpack(args)}, spec)
|
||||
end
|
||||
|
||||
Obj.update_abbrev_head = function(self: Obj)
|
||||
@ -326,7 +260,7 @@ Obj.file_info = function(self: Obj, file: string): string, string, string, boole
|
||||
end
|
||||
|
||||
Obj.unstage_file = function(self: Obj)
|
||||
self:command{'reset', self.file }
|
||||
self:command{'reset', self.file }
|
||||
end
|
||||
|
||||
--- Get version of file in the index, return array lines
|
||||
@ -336,24 +270,6 @@ Obj.get_show_text = function(self: Obj, object: string): {string}, string
|
||||
})
|
||||
end
|
||||
|
||||
--- Get version of file in the index, write lines to file
|
||||
Obj.get_show = function(self: Obj, object: string, output_file: string)
|
||||
-- On windows 'w' mode use \r\n instead of \n, see:
|
||||
-- https://stackoverflow.com/a/43967013
|
||||
local outf, err = io.open(output_file, 'wb')
|
||||
if outf == nil then
|
||||
error(err)
|
||||
end
|
||||
self:command({'show', object}, {
|
||||
supress_stderr = true,
|
||||
on_stdout = function(_, line: string)
|
||||
outf:write(line)
|
||||
outf:write('\n')
|
||||
end
|
||||
})
|
||||
outf:close()
|
||||
end
|
||||
|
||||
Obj.run_blame = function(self: Obj, lines: {string}, lnum: number): M.BlameInfo
|
||||
local results = self:command({
|
||||
'blame',
|
||||
@ -431,14 +347,14 @@ Obj.new = function(file: string): Obj
|
||||
local self = setmetatable({} as Obj, {__index = Obj})
|
||||
|
||||
self.file = file
|
||||
self.username = command({'config', 'user.name'})[1]
|
||||
self.username = M.command({'config', 'user.name'})[1]
|
||||
self.toplevel, self.gitdir, self.abbrev_head =
|
||||
get_repo_info(util.dirname(file))
|
||||
|
||||
-- Try yadm
|
||||
if M.enable_yadm and not self.gitdir then
|
||||
if vim.startswith(file, os.getenv('HOME'))
|
||||
and #command({'ls-files', file}, {command = 'yadm'}) ~= 0 then
|
||||
and #M.command({'ls-files', file}, {command = 'yadm'}) ~= 0 then
|
||||
self.toplevel, self.gitdir, self.abbrev_head =
|
||||
get_repo_info(util.dirname(file), 'yadm')
|
||||
end
|
||||
|
@ -17,8 +17,10 @@ local gs_debug = require("gitsigns.debug")
|
||||
local dprint = gs_debug.dprint
|
||||
local eprint = gs_debug.eprint
|
||||
local util = require('gitsigns.util')
|
||||
local git = require('gitsigns.git')
|
||||
|
||||
local gs_hunks = require("gitsigns.hunks")
|
||||
local Hunk = gs_hunks.Hunk
|
||||
|
||||
local setup_highlight = require('gitsigns.highlight').setup_highlight
|
||||
|
||||
local config = require('gitsigns.config').config
|
||||
@ -148,7 +150,7 @@ M.apply_word_diff = function(bufnr: integer, row: integer)
|
||||
for _, hunk in ipairs(cache[bufnr].hunks) do
|
||||
if lnum >= hunk.start and lnum <= hunk.vend then
|
||||
local size = #hunk.lines / 2
|
||||
local regions = require('gitsigns.diff').run_word_diff(hunk.lines)
|
||||
local regions = require('gitsigns.diff_ffi').run_word_diff(hunk.lines)
|
||||
for _, region in ipairs(regions) do
|
||||
local line = region[1]
|
||||
if lnum == hunk.start + line - size - 1
|
||||
@ -192,16 +194,17 @@ local update0 = function(bufnr: integer, bcache: CacheEntry)
|
||||
|
||||
local compare_object = bcache.get_compare_obj(bcache)
|
||||
|
||||
if config.use_internal_diff then
|
||||
local diff = require('gitsigns.diff')
|
||||
if not bcache.compare_text or config._refresh_staged_on_update then
|
||||
bcache.compare_text = git_obj:get_show_text(compare_object)
|
||||
end
|
||||
bcache.hunks = diff.run_diff(bcache.compare_text, buftext, config.diff_algorithm)
|
||||
else
|
||||
git_obj:get_show(compare_object, bcache.compare_file)
|
||||
bcache.hunks = git.run_diff(bcache.compare_file, buftext, config.diff_algorithm)
|
||||
if not bcache.compare_text or config._refresh_staged_on_update then
|
||||
bcache.compare_text = git_obj:get_show_text(compare_object)
|
||||
end
|
||||
|
||||
local run_diff: function({string}, {string}, string): {Hunk}
|
||||
if config.use_internal_diff then
|
||||
run_diff = require('gitsigns.diff_ffi').run_diff
|
||||
else
|
||||
run_diff = require('gitsigns.diff_ext').run_diff
|
||||
end
|
||||
bcache.hunks = run_diff(bcache.compare_text, buftext, config.diff_algorithm)
|
||||
bcache.pending_signs = gs_hunks.process_hunks(bcache.hunks)
|
||||
|
||||
scheduler()
|
||||
|
Loading…
Reference in New Issue
Block a user