mirror of
https://github.com/lewis6991/gitsigns.nvim
synced 2025-02-21 15:27:09 +00:00
parent
672482df3e
commit
11425117a9
10
lua/gitsigns.lua
generated
10
lua/gitsigns.lua
generated
@ -521,11 +521,11 @@ M.setup = void(function(cfg)
|
||||
end
|
||||
manager.apply_win_signs(bufnr, bcache.pending_signs, top + 1, bot + 1)
|
||||
|
||||
|
||||
return config.word_diff and config.diff_opts.internal
|
||||
end,
|
||||
on_line = function(_, _, bufnr, row)
|
||||
manager.apply_word_diff(bufnr, row)
|
||||
if config.word_diff and config.diff_opts.internal then
|
||||
for i = top, bot do
|
||||
manager.apply_word_diff(bufnr, i)
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
|
47
lua/gitsigns/diff_int.lua
generated
47
lua/gitsigns/diff_int.lua
generated
@ -49,6 +49,26 @@ local Region = {}
|
||||
|
||||
local gaps_between_regions = 5
|
||||
|
||||
local function denoise_hunks(hunks)
|
||||
|
||||
local ret = { hunks[1] }
|
||||
for j = 2, #hunks do
|
||||
local h, n = ret[#ret], hunks[j]
|
||||
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
|
||||
ret[#ret + 1] = n
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function M.run_word_diff(removed, added)
|
||||
local adds = {}
|
||||
local rems = {}
|
||||
@ -59,12 +79,9 @@ function M.run_word_diff(removed, added)
|
||||
|
||||
for i = 1, #removed do
|
||||
|
||||
local rline = removed[i]
|
||||
local aline = added[i]
|
||||
local a, b = vim.split(removed[i], ''), vim.split(added[i], '')
|
||||
|
||||
local a, b = vim.split(rline, ''), vim.split(aline, '')
|
||||
|
||||
local hunks0 = {}
|
||||
local hunks = {}
|
||||
for _, r in ipairs(run_diff_xdl(a, b)) do
|
||||
local rs, rc, as, ac = unpack(r)
|
||||
|
||||
@ -72,26 +89,10 @@ function M.run_word_diff(removed, added)
|
||||
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)
|
||||
hunks[#hunks + 1] = create_hunk(rs, rc, as, ac)
|
||||
end
|
||||
|
||||
|
||||
local hunks = { hunks0[1] }
|
||||
for j = 2, #hunks0 do
|
||||
local h, n = hunks[#hunks], hunks0[j]
|
||||
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
|
||||
hunks = denoise_hunks(hunks)
|
||||
|
||||
for _, h in ipairs(hunks) do
|
||||
adds[#adds + 1] = { i + #removed, h.type, h.added.start, h.added.start + h.added.count }
|
||||
|
72
lua/gitsigns/manager.lua
generated
72
lua/gitsigns/manager.lua
generated
@ -175,40 +175,56 @@ end
|
||||
local ns = api.nvim_create_namespace('gitsigns')
|
||||
|
||||
M.apply_word_diff = function(bufnr, row)
|
||||
if not cache[bufnr] or not cache[bufnr].hunks then return end
|
||||
if not cache[bufnr] or not cache[bufnr].hunks then
|
||||
return
|
||||
end
|
||||
|
||||
local line = api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1]
|
||||
if not line then
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local lnum = row + 1
|
||||
local cols = #api.nvim_buf_get_lines(bufnr, lnum - 1, lnum, false)[1]
|
||||
|
||||
for _, hunk in ipairs(cache[bufnr].hunks) do
|
||||
if lnum >= hunk.start and lnum <= hunk.vend then
|
||||
local size = (#hunk.added.lines + #hunk.removed.lines) / 2
|
||||
local removed_regions, added_regions = require('gitsigns.diff_int').run_word_diff(hunk.removed.lines, hunk.added.lines)
|
||||
local regions = vim.list_extend(removed_regions or {}, added_regions or {})
|
||||
for _, region in ipairs(regions) do
|
||||
local line = region[1]
|
||||
if lnum == hunk.start + line - size - 1 then
|
||||
local hunk = gs_hunks.find_hunk(lnum, cache[bufnr].hunks)
|
||||
if not hunk then
|
||||
|
||||
local rtype, scol, ecol = region[2], region[3], region[4]
|
||||
if scol <= cols then
|
||||
if ecol > cols then
|
||||
ecol = cols
|
||||
elseif ecol == scol then
|
||||
return
|
||||
end
|
||||
|
||||
ecol = scol + 1
|
||||
end
|
||||
api.nvim_buf_set_extmark(bufnr, ns, row, scol - 1, {
|
||||
end_col = ecol - 1,
|
||||
hl_group = rtype == 'add' and 'GitSignsAddLnInline' or
|
||||
rtype == 'change' and 'GitSignsChangeLnInline' or
|
||||
'GitSignsDeleteLnInline',
|
||||
ephemeral = true,
|
||||
priority = 1000,
|
||||
})
|
||||
end
|
||||
end
|
||||
if hunk.added.count ~= hunk.removed.count then
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local pos = lnum - hunk.start + 1
|
||||
|
||||
local added_line = hunk.added.lines[pos]
|
||||
local removed_line = hunk.removed.lines[pos]
|
||||
|
||||
local _, added_regions = require('gitsigns.diff_int').run_word_diff({ removed_line }, { added_line })
|
||||
|
||||
local cols = #line
|
||||
|
||||
for _, region in ipairs(added_regions) do
|
||||
local rtype, scol, ecol = region[2], region[3], region[4]
|
||||
if scol <= cols then
|
||||
if ecol > cols then
|
||||
ecol = cols
|
||||
elseif ecol == scol then
|
||||
|
||||
ecol = scol + 1
|
||||
end
|
||||
break
|
||||
api.nvim_buf_set_extmark(bufnr, ns, row, scol - 1, {
|
||||
end_col = ecol - 1,
|
||||
hl_group = rtype == 'add' and 'GitSignsAddLnInline' or
|
||||
rtype == 'change' and 'GitSignsChangeLnInline' or
|
||||
'GitSignsDeleteLnInline',
|
||||
ephemeral = true,
|
||||
priority = 1000,
|
||||
})
|
||||
api.nvim__buf_redraw_range(bufnr, row, row + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -521,11 +521,11 @@ M.setup = void(function(cfg: Config)
|
||||
end
|
||||
manager.apply_win_signs(bufnr, bcache.pending_signs, top+1, bot+1)
|
||||
|
||||
-- Returning false prevents the on_line callbacks
|
||||
return config.word_diff and config.diff_opts.internal
|
||||
end,
|
||||
on_line = function(_, _, bufnr: integer, row: integer)
|
||||
manager.apply_word_diff(bufnr, row)
|
||||
if config.word_diff and config.diff_opts.internal then
|
||||
for i = top, bot do
|
||||
manager.apply_word_diff(bufnr, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
|
@ -49,6 +49,26 @@ local type Region = {integer, string, integer, integer}
|
||||
|
||||
local gaps_between_regions = 5
|
||||
|
||||
local function denoise_hunks(hunks: {Hunk}): {Hunk}
|
||||
-- Denoise the hunks
|
||||
local ret = {hunks[1]}
|
||||
for j = 2, #hunks do
|
||||
local h, n = ret[#ret], hunks[j]
|
||||
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
|
||||
ret[#ret+1] = n
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function M.run_word_diff(removed: {string}, added: {string}): {Region}, {Region}
|
||||
local adds: {Region} = {}
|
||||
local rems: {Region} = {}
|
||||
@ -59,12 +79,9 @@ function M.run_word_diff(removed: {string}, added: {string}): {Region}, {Region}
|
||||
|
||||
for i = 1, #removed do
|
||||
-- pair lines by position
|
||||
local rline = removed[i]
|
||||
local aline = added[i]
|
||||
local a, b = vim.split(removed[i], ''), vim.split(added[i], '')
|
||||
|
||||
local a, b = vim.split(rline, ''), vim.split(aline, '')
|
||||
|
||||
local hunks0: {Hunk} = {}
|
||||
local hunks: {Hunk} = {}
|
||||
for _, r in ipairs(run_diff_xdl(a, b)) do
|
||||
local rs, rc, as, ac = unpack(r)
|
||||
|
||||
@ -72,26 +89,10 @@ function M.run_word_diff(removed: {string}, added: {string}): {Region}, {Region}
|
||||
if rc == 0 then rs = rs + 1 end
|
||||
if ac == 0 then as = as + 1 end
|
||||
|
||||
-- print(string.format('-%d,%d +%d,%d', rs, rc, as, ac))
|
||||
hunks0[#hunks0+1] = create_hunk(rs, rc, as, ac)
|
||||
hunks[#hunks+1] = create_hunk(rs, rc, as, ac)
|
||||
end
|
||||
|
||||
-- Denoise the hunks
|
||||
local hunks = {hunks0[1]}
|
||||
for j = 2, #hunks0 do
|
||||
local h, n = hunks[#hunks], hunks0[j]
|
||||
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
|
||||
hunks = denoise_hunks(hunks)
|
||||
|
||||
for _, h in ipairs(hunks) do
|
||||
adds[#adds+1] = {i+#removed, h.type, h.added.start , h.added.start + h.added.count}
|
||||
|
@ -175,40 +175,56 @@ end
|
||||
local ns = api.nvim_create_namespace('gitsigns')
|
||||
|
||||
M.apply_word_diff = function(bufnr: integer, row: integer)
|
||||
if not cache[bufnr] or not cache[bufnr].hunks then return end
|
||||
if not cache[bufnr] or not cache[bufnr].hunks then
|
||||
return
|
||||
end
|
||||
|
||||
local line = api.nvim_buf_get_lines(bufnr, row, row+1, false)[1]
|
||||
if not line then
|
||||
-- Invalid line
|
||||
return
|
||||
end
|
||||
|
||||
local lnum = row + 1
|
||||
local cols = #api.nvim_buf_get_lines(bufnr, lnum-1, lnum, false)[1]
|
||||
|
||||
for _, hunk in ipairs(cache[bufnr].hunks) do
|
||||
if lnum >= hunk.start and lnum <= hunk.vend then
|
||||
local size = (#hunk.added.lines +#hunk.removed.lines) / 2
|
||||
local removed_regions, added_regions = require('gitsigns.diff_int').run_word_diff(hunk.removed.lines, hunk.added.lines)
|
||||
local regions = vim.list_extend(removed_regions or {}, added_regions or {})
|
||||
for _, region in ipairs(regions) do
|
||||
local line = region[1]
|
||||
if lnum == hunk.start + line - size - 1 then
|
||||
-- and vim.startswith(hunk.lines[line], '+') then
|
||||
local rtype, scol, ecol = region[2], region[3], region[4]
|
||||
if scol <= cols then
|
||||
if ecol > cols then
|
||||
ecol = cols
|
||||
elseif ecol == scol then
|
||||
-- Make sure region is at least 1 column width
|
||||
ecol = scol + 1
|
||||
end
|
||||
api.nvim_buf_set_extmark(bufnr, ns, row, scol-1, {
|
||||
end_col = ecol-1,
|
||||
hl_group = rtype == 'add' and 'GitSignsAddLnInline'
|
||||
or rtype == 'change' and 'GitSignsChangeLnInline'
|
||||
or 'GitSignsDeleteLnInline',
|
||||
ephemeral = true,
|
||||
priority = 1000
|
||||
})
|
||||
end
|
||||
end
|
||||
local hunk = gs_hunks.find_hunk(lnum, cache[bufnr].hunks)
|
||||
if not hunk then
|
||||
-- No hunk at line
|
||||
return
|
||||
end
|
||||
|
||||
if hunk.added.count ~= hunk.removed.count then
|
||||
-- Only word diff if added count == removed
|
||||
return
|
||||
end
|
||||
|
||||
local pos = lnum - hunk.start + 1
|
||||
|
||||
local added_line = hunk.added.lines[pos]
|
||||
local removed_line = hunk.removed.lines[pos]
|
||||
|
||||
local _, added_regions = require('gitsigns.diff_int').run_word_diff({removed_line}, {added_line})
|
||||
|
||||
local cols = #line
|
||||
|
||||
for _, region in ipairs(added_regions) do
|
||||
local rtype, scol, ecol = region[2], region[3], region[4]
|
||||
if scol <= cols then
|
||||
if ecol > cols then
|
||||
ecol = cols
|
||||
elseif ecol == scol then
|
||||
-- Make sure region is at least 1 column width
|
||||
ecol = scol + 1
|
||||
end
|
||||
break
|
||||
api.nvim_buf_set_extmark(bufnr, ns, row, scol-1, {
|
||||
end_col = ecol-1,
|
||||
hl_group = rtype == 'add' and 'GitSignsAddLnInline'
|
||||
or rtype == 'change' and 'GitSignsChangeLnInline'
|
||||
or 'GitSignsDeleteLnInline',
|
||||
ephemeral = true,
|
||||
priority = 1000
|
||||
})
|
||||
api.nvim__buf_redraw_range(bufnr, row, row+1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user