Skip to content

Commit

Permalink
feat(diffopt): add support for whitespace flags in diffopt
Browse files Browse the repository at this point in the history
Resolves #696
  • Loading branch information
lewis6991 committed Oct 2, 2023
1 parent e32efa6 commit 648fe05
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 50 deletions.
10 changes: 10 additions & 0 deletions doc/gitsigns.txt
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,16 @@ diff_opts *gitsigns-config-diff_opts*
• linematch: integer
Enable second-stage diff on hunks to align lines.
Requires `internal=true`.
• ignore_blank_lines: boolean
Ignore changes where lines are blank.
• ignore_whitespace_change: boolean
Ignore changes in amount of white space.
It should ignore adding trailing white space,
but not leading white space.
• ignore_whitespace: boolean
Ignore all white space changes.
• ignore_whitespace_change_at_eol: boolean
Ignore white space changes at end of line.

base *gitsigns-config-base*
Type: `string`, Default: index
Expand Down
86 changes: 60 additions & 26 deletions lua/gitsigns/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
--- @field default_help? string
--- @field description string

--- @class Gitsigns.DiffOpts
--- @class (exact) Gitsigns.DiffOpts
--- @field algorithm string
--- @field internal boolean
--- @field indent_heuristic boolean
--- @field vertical boolean
--- @field linematch integer
--- @field linematch? integer
--- @field ignore_whitespace_change? true
--- @field ignore_whitespace? true
--- @field ignore_whitespace_change_at_eol? true
--- @field ignore_blank_lines? true

--- @class Gitsigns.SignConfig
--- @field show_count boolean
Expand Down Expand Up @@ -99,6 +103,41 @@ local function resolve_default(v)
end
end

--- @return Gitsigns.DiffOpts
local function parse_diffopt()
--- @type Gitsigns.DiffOpts
local r = {
algorithm = 'myers',
internal = false,
indent_heuristic = false,
vertical = true,
}

local optmap = {
['indent-heuristic'] = 'indent_heuristic',
internal = 'internal',
iwhite = 'ignore_whitespace_change',
iblank = 'ignore_blank_lines',
iwhiteeol = 'ignore_whitespace_change_at_eol',
iwhiteall = 'ignore_whitespace',
}

local diffopt = vim.opt.diffopt:get() --[[@as string[] ]]
for _, o in ipairs(diffopt) do
if optmap[o] then
r[optmap[o]] = true
elseif o == 'horizontal' then
r.vertical = false
elseif vim.startswith(o, 'algorithm:') then
r.algorithm = string.sub(o, ('algorithm:'):len() + 1)
elseif vim.startswith(o, 'linematch:') then
r.linematch = tonumber(string.sub(o, ('linematch:'):len() + 1))
end
end

return r
end

--- @type Gitsigns.Config
M.config = setmetatable({}, {
__index = function(t, k)
Expand Down Expand Up @@ -378,30 +417,15 @@ M.schema = {
type = 'table',
deep_extend = true,
default = function()
local r = {
algorithm = 'myers',
internal = false,
indent_heuristic = false,
vertical = true,
linematch = nil,
}
local diffopt = vim.opt.diffopt:get() --[[@as string[] ]]
for _, o in ipairs(diffopt) do
if o == 'indent-heuristic' then
r.indent_heuristic = true
elseif o == 'internal' then
if vim.diff then
r.internal = true
end
elseif o == 'horizontal' then
r.vertical = false
elseif vim.startswith(o, 'algorithm:') then
r.algorithm = string.sub(o, ('algorithm:'):len() + 1)
elseif vim.startswith(o, 'linematch:') then
r.linematch = tonumber(string.sub(o, ('linematch:'):len() + 1))
end
end
return r
vim.api.nvim_create_autocmd('OptionSet', {
group = vim.api.nvim_create_augroup('gitsigns.config.diff_opts', {}),
pattern = 'diffopt',
callback = function()
M.config.diff_opts = parse_diffopt()
end,
})

return parse_diffopt()
end,
default_help = "derived from 'diffopt'",
description = [[
Expand All @@ -425,6 +449,16 @@ M.schema = {
• linematch: integer
Enable second-stage diff on hunks to align lines.
Requires `internal=true`.
• ignore_blank_lines: boolean
Ignore changes where lines are blank.
• ignore_whitespace_change: boolean
Ignore changes in amount of white space.
It should ignore adding trailing white space,
but not leading white space.
• ignore_whitespace: boolean
Ignore all white space changes.
• ignore_whitespace_change_at_eol: boolean
Ignore white space changes at end of line.
]],
},

Expand Down
4 changes: 2 additions & 2 deletions lua/gitsigns/diff.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
local config = require('gitsigns.config').config

--- @alias Gitsigns.Difffn fun(fa: string[], fb: string[], algorithm?: string, indent_heuristic?: boolean, linematch?: integer): Gitsigns.Hunk.Hunk[]
--- @alias Gitsigns.Difffn fun(fa: string[], fb: string[], linematch?: integer): Gitsigns.Hunk.Hunk[]

--- @param a string[]
--- @param b string[]
Expand Down Expand Up @@ -28,5 +28,5 @@ return function(a, b, linematch)
linematch0 = diff_opts.linematch
end

return f(a, b, diff_opts.algorithm, diff_opts.indent_heuristic, linematch0)
return f(a, b, linematch0)
end
8 changes: 4 additions & 4 deletions lua/gitsigns/diff_ext.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
local config = require('gitsigns.config').config
local git_diff = require('gitsigns.git').diff

local gs_hunks = require('gitsigns.hunks')
Expand All @@ -24,10 +25,8 @@ end
--- @async
--- @param text_cmp string[]
--- @param text_buf string[]
--- @param diff_algo string
--- @param indent_heuristic? boolean
--- @return Gitsigns.Hunk.Hunk[]
function M.run_diff(text_cmp, text_buf, diff_algo, indent_heuristic)
function M.run_diff(text_cmp, text_buf)
local results = {} --- @type Gitsigns.Hunk.Hunk[]

-- tmpname must not be called in a callback
Expand Down Expand Up @@ -57,7 +56,8 @@ function M.run_diff(text_cmp, text_buf, diff_algo, indent_heuristic)
-- We can safely ignore the warning, we turn it off by passing the '-c
-- "core.safecrlf=false"' argument to git-diff.

local out = git_diff(file_cmp, file_buf, indent_heuristic, diff_algo)
local opts = config.diff_opts
local out = git_diff(file_cmp, file_buf, opts.indent_heuristic, opts.algorithm)

for _, line in ipairs(out) do
if vim.startswith(line, '@@') then
Expand Down
56 changes: 38 additions & 18 deletions lua/gitsigns/diff_int.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,19 @@ local M = {}
--- @alias Gitsigns.Region {[1]:integer, [2]:string, [3]:integer, [4]:integer}

--- @alias Gitsigns.RawHunk {[1]:integer, [2]:integer, [3]:integer, [4]:integer}
--- @alias Gitsigns.RawDifffn fun(a: string, b: string, algorithm?: string, indent_heuristic?: boolean, linematch?: integer): Gitsigns.RawHunk[]
--- @alias Gitsigns.RawDifffn fun(a: string, b: string, linematch?: integer): Gitsigns.RawHunk[]

--- @type Gitsigns.RawDifffn
local run_diff_xdl = function(a, b, algorithm, indent_heuristic, linematch)
local run_diff_xdl = function(a, b, linematch)
local opts = config.diff_opts
return vim.diff(a, b, {
result_type = 'indices',
algorithm = algorithm,
indent_heuristic = indent_heuristic,
algorithm = opts.algorithm,
indent_heuristic = opts.indent_heuristic,
ignore_whitespace = opts.ignore_whitespace,
ignore_whitespace_change = opts.ignore_whitespace_change,
ignore_whitespace_change_at_eol = opts.ignore_whitespace_change_at_eol,
ignore_blank_lines = opts.ignore_blank_lines,
linematch = linematch,
}) --[[@as Gitsigns.RawHunk[] ]]
end
Expand All @@ -23,45 +28,60 @@ end
local run_diff_xdl_async = async.wrap(
--- @param a string
--- @param b string
--- @param algorithm? string
--- @param indent_heuristic? boolean
--- @param linematch? integer
--- @param callback fun(hunks: Gitsigns.RawHunk[])
function(a, b, algorithm, indent_heuristic, linematch, callback)
function(a, b, linematch, callback)
local opts = config.diff_opts
local function toflag(f, pos)
return f and bit.lshift(1, pos) or 0
end

local flags = toflag(opts.indent_heuristic, 0)
+ toflag(opts.ignore_whitespace, 1)
+ toflag(opts.ignore_whitespace_change, 2)
+ toflag(opts.ignore_whitespace_change_at_eol, 3)
+ toflag(opts.ignore_blank_lines, 4)

vim.loop
.new_work(
--- @param a0 string
--- @param b0 string
--- @param algorithm0 string
--- @param indent_heuristic0 integer
--- @param algorithm string
--- @param flags0 integer
--- @param linematch0 integer
--- @return string
function(a0, b0, algorithm0, indent_heuristic0, linematch0)
function(a0, b0, algorithm, flags0, linematch0)
local function flagval(pos)
return bit.band(flags0, bit.lshift(1, pos)) ~= 0
end

--- @diagnostic disable-next-line:return-type-mismatch
return vim.mpack.encode(vim.diff(a0, b0, {
result_type = 'indices',
algorithm = algorithm0,
indent_heuristic = indent_heuristic0,
algorithm = algorithm,
linematch = linematch0,
indent_heuristic = flagval(0),
ignore_whitespace = flagval(1),
ignore_whitespace_change = flagval(2),
ignore_whitespace_change_at_eol = flagval(3),
ignore_blank_lines = flagval(4),
}))
end,
--- @param r string
function(r)
callback(vim.mpack.decode(r) --[[@as Gitsigns.RawHunk[] ]])
end
)
:queue(a, b, algorithm, indent_heuristic, linematch)
:queue(a, b, opts.algorithm, flags, linematch)
end,
6
4
)

--- @param fa string[]
--- @param fb string[]
--- @param diff_algo? string
--- @param indent_heuristic? boolean
--- @param linematch? integer
--- @return Gitsigns.Hunk.Hunk[]
function M.run_diff(fa, fb, diff_algo, indent_heuristic, linematch)
function M.run_diff(fa, fb, linematch)
local run_diff0 --- @type Gitsigns.RawDifffn
if config._threaded_diff and vim.is_thread then
run_diff0 = run_diff_xdl_async
Expand All @@ -72,7 +92,7 @@ function M.run_diff(fa, fb, diff_algo, indent_heuristic, linematch)
local a = table.concat(fa, '\n')
local b = table.concat(fb, '\n')

local results = run_diff0(a, b, diff_algo, indent_heuristic, linematch)
local results = run_diff0(a, b, linematch)

local hunks = {} --- @type Gitsigns.Hunk.Hunk[]
for _, r in ipairs(results) do
Expand Down

0 comments on commit 648fe05

Please sign in to comment.