diff --git a/doc/gitsigns.txt b/doc/gitsigns.txt index 9c8d8cc..3bf645b 100644 --- a/doc/gitsigns.txt +++ b/doc/gitsigns.txt @@ -415,18 +415,16 @@ signs *gitsigns-config-signs* • `show_count` to enable showing count of hunk, e.g. number of deleted lines. - Note if `hl`, `numhl` or `linehl` use a `GitSigns*` highlight and it is - not defined, it will be automatically derived by searching for other - defined highlights in the following order: + Note if a highlight is not defined, it will be automatically derived by + searching for other defined highlights in the following order: • `GitGutter*` • `Signify*` • `Diff*Gutter` • `diff*` • `Diff*` - For example if `signs.add.hl = GitSignsAdd` and `GitSignsAdd` is not - defined but `GitGutterAdd` is defined, then `GitSignsAdd` will be linked - to `GitGutterAdd`. + For example if `GitSignsAdd` is not defined but `GitGutterAdd` is defined, + then `GitSignsAdd` will be linked to `GitGutterAdd`. keymaps *gitsigns-config-keymaps* DEPRECATED @@ -744,9 +742,18 @@ word_diff *gitsigns-config-word_diff* Requires `config.diff_opts.internal = true` . Uses the highlights: - • GitSignsAddLn - • GitSignsChangeLn - • GitSignsDeleteLn + • For word diff in previews: + • `GitSignsAddInline` + • `GitSignsChangeInline` + • `GitSignsDeleteInline` + • For word diff in buffer: + • `GitSignsAddLnInline` + • `GitSignsChangeLnInline` + • `GitSignsDeleteLnInline` + • For word diff in virtual lines (e.g. show_deleted): + • `GitSignsAddVirtLnInline` + • `GitSignsChangeVirtLnInline` + • `GitSignsDeleteVirtLnInline` debug_mode *gitsigns-config-debug_mode* Type: `boolean`, Default: `false` diff --git a/lua/gitsigns/actions.lua b/lua/gitsigns/actions.lua index 6326190..6927c76 100644 --- a/lua/gitsigns/actions.lua +++ b/lua/gitsigns/actions.lua @@ -21,6 +21,7 @@ local Hunk_Public = gs_hunks.Hunk_Public local api = vim.api local current_buf = api.nvim_get_current_buf +local add_highlight = api.nvim_buf_add_highlight local NavHunkOpts = {} @@ -437,17 +438,21 @@ end local function highlight_hunk_lines(bufnr, offset, hunk) for i = 1, #hunk.removed.lines do - api.nvim_buf_add_highlight(bufnr, -1, 'DiffRemoved', offset + i - 1, 0, -1) + add_highlight(bufnr, -1, 'GitSignsDeleteLn', offset + i - 1, 0, -1) end for i = 1, #hunk.added.lines do - api.nvim_buf_add_highlight(bufnr, -1, 'DiffAdded', #hunk.removed.lines + offset + i - 1, 0, -1) + add_highlight(bufnr, -1, 'GitSignsAddLn', #hunk.removed.lines + offset + i - 1, 0, -1) end if config.diff_opts.internal then - local regions = require('gitsigns.diff_int').run_word_diff(hunk.removed.lines, hunk.added.lines) - for _, region in ipairs(regions) do + local removed_regions, added_regions = require('gitsigns.diff_int').run_word_diff(hunk.removed.lines, hunk.added.lines) + for _, region in ipairs(removed_regions) do local line, scol, ecol = region[1], region[3], region[4] - api.nvim_buf_add_highlight(bufnr, -1, 'TermCursor', line + offset - 1, scol, ecol) + add_highlight(bufnr, -1, 'GitSignsDeleteInline', line + offset - 1, scol, ecol) + end + for _, region in ipairs(added_regions) do + local line, scol, ecol = region[1], region[3], region[4] + add_highlight(bufnr, -1, 'GitSignsAddInline', line + offset - 1, scol, ecol) end end end @@ -499,7 +504,7 @@ M.preview_hunk = noautocmd(function() local _, bufnr = popup.create(lines, config.preview_config) - api.nvim_buf_add_highlight(bufnr, -1, 'Title', 0, 0, -1) + add_highlight(bufnr, -1, 'Title', 0, 0, -1) api.nvim_buf_set_var(cbuf, '_gitsigns_preview_open', true) vim.cmd([[autocmd CursorMoved,CursorMovedI ++once silent! unlet b:_gitsigns_preview_open]]) @@ -637,7 +642,7 @@ M.blame_line = void(function(opts) local highlights = {} - local function add_highlight(hlgroup, start, length) + local function add_hl(hlgroup, start, length) highlights[#highlights + 1] = { hlgroup, #lines - 1, start or 0, length or -1 } end @@ -660,9 +665,9 @@ M.blame_line = void(function(opts) local p2 = #result.author local p3 = #date - add_highlight('Directory', 0, p1) - add_highlight('MoreMsg', p1 + 1, p2) - add_highlight('Label', p1 + p2 + 2, p3 + 2) + add_hl('Directory', 0, p1) + add_hl('MoreMsg', p1 + 1, p2) + add_hl('Label', p1 + p2 + 2, p3 + 2) vim.list_extend(lines, commit_message) @@ -671,7 +676,7 @@ M.blame_line = void(function(opts) end else lines[#lines + 1] = result.author - add_highlight('ErrorMsg') + add_hl('ErrorMsg') if full then scheduler() hunk, ihunk = get_cursor_hunk(bufnr, bcache.hunks) @@ -682,7 +687,7 @@ M.blame_line = void(function(opts) if hunk then lines[#lines + 1] = '' lines[#lines + 1] = ('Hunk %d of %d'):format(ihunk, nhunk) - add_highlight('Title') + add_hl('Title') vim.list_extend(lines, gs_hunks.patch_lines(hunk)) end @@ -691,7 +696,7 @@ M.blame_line = void(function(opts) for _, h in ipairs(highlights) do local hlgroup, line, start, length = h[1], h[2], h[3], h[4] - api.nvim_buf_add_highlight(pbufnr, -1, hlgroup, line, start, start + length) + add_highlight(pbufnr, -1, hlgroup, line, start, start + length) end if hunk then diff --git a/lua/gitsigns/config.lua b/lua/gitsigns/config.lua index 6439b27..031c028 100644 --- a/lua/gitsigns/config.lua +++ b/lua/gitsigns/config.lua @@ -131,18 +131,16 @@ M.schema = { • `show_count` to enable showing count of hunk, e.g. number of deleted lines. - Note if `hl`, `numhl` or `linehl` use a `GitSigns*` highlight and it is - not defined, it will be automatically derived by searching for other - defined highlights in the following order: + Note if a highlight is not defined, it will be automatically derived by + searching for other defined highlights in the following order: • `GitGutter*` • `Signify*` • `Diff*Gutter` • `diff*` • `Diff*` - For example if `signs.add.hl = GitSignsAdd` and `GitSignsAdd` is not - defined but `GitGutterAdd` is defined, then `GitSignsAdd` will be linked - to `GitGutterAdd`. + For example if `GitSignsAdd` is not defined but `GitGutterAdd` is defined, + then `GitSignsAdd` will be linked to `GitGutterAdd`. ]], }, @@ -591,9 +589,18 @@ M.schema = { Requires `config.diff_opts.internal = true` . Uses the highlights: - • GitSignsAddLn - • GitSignsChangeLn - • GitSignsDeleteLn + • For word diff in previews: + • `GitSignsAddInline` + • `GitSignsChangeInline` + • `GitSignsDeleteInline` + • For word diff in buffer: + • `GitSignsAddLnInline` + • `GitSignsChangeLnInline` + • `GitSignsDeleteLnInline` + • For word diff in virtual lines (e.g. show_deleted): + • `GitSignsAddVirtLnInline` + • `GitSignsChangeVirtLnInline` + • `GitSignsDeleteVirtLnInline` ]], }, diff --git a/lua/gitsigns/diff_int.lua b/lua/gitsigns/diff_int.lua index 20c5f95..a782f46 100644 --- a/lua/gitsigns/diff_int.lua +++ b/lua/gitsigns/diff_int.lua @@ -50,11 +50,12 @@ local Region = {} local gaps_between_regions = 5 function M.run_word_diff(removed, added) - if #removed ~= #added then - return {} - end + local adds = {} + local rems = {} - local ret = {} + if #removed ~= #added then + return rems, adds + end for i = 1, #removed do @@ -93,14 +94,11 @@ function M.run_word_diff(removed, added) 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 + adds[#adds + 1] = { i + #removed, h.type, h.added.start, h.added.start + h.added.count } + rems[#rems + 1] = { i, h.type, h.removed.start, h.removed.start + h.removed.count } end end - return ret + return rems, adds end return M diff --git a/lua/gitsigns/highlight.lua b/lua/gitsigns/highlight.lua index 48c89a4..977909b 100644 --- a/lua/gitsigns/highlight.lua +++ b/lua/gitsigns/highlight.lua @@ -7,71 +7,65 @@ local M = {} -local GitSignHl = {} - - - - - - - - - - - - - - local hls = { - GitSignsAdd = { 'GitGutterAdd', 'SignifySignAdd', 'DiffAddedGutter', 'diffAdded', 'DiffAdd' }, - GitSignsChange = { 'GitGutterChange', 'SignifySignChange', 'DiffModifiedGutter', 'diffChanged', 'DiffChange' }, - GitSignsDelete = { 'GitGutterDelete', 'SignifySignDelete', 'DiffRemovedGutter', 'diffRemoved', 'DiffDelete' }, + { GitSignsAdd = { 'GitGutterAdd', 'SignifySignAdd', 'DiffAddedGutter', 'diffAdded', 'DiffAdd' } }, + { GitSignsChange = { 'GitGutterChange', 'SignifySignChange', 'DiffModifiedGutter', 'diffChanged', 'DiffChange' } }, + { GitSignsDelete = { 'GitGutterDelete', 'SignifySignDelete', 'DiffRemovedGutter', 'diffRemoved', 'DiffDelete' } }, - GitSignsAddNr = { 'GitGutterAddLineNr', 'GitSignsAdd', 'SignifySignAdd', 'DiffAddedGutter', 'diffAdded', 'DiffAdd' }, - GitSignsChangeNr = { 'GitGutterChangeLineNr', 'GitSignsChange', 'SignifySignChange', 'DiffModifiedGutter', 'diffChanged', 'DiffChange' }, - GitSignsDeleteNr = { 'GitGutterDeleteLineNr', 'GitSignsDelete', 'SignifySignDelete', 'DiffRemovedGutter', 'diffRemoved', 'DiffDelete' }, + { GitSignsAddNr = { 'GitGutterAddLineNr', 'GitSignsAdd' } }, + { GitSignsChangeNr = { 'GitGutterChangeLineNr', 'GitSignsChange' } }, + { GitSignsDeleteNr = { 'GitGutterDeleteLineNr', 'GitSignsDelete' } }, - GitSignsAddLn = { 'GitGutterAddLine', 'SignifyLineAdd', 'DiffAdd' }, - GitSignsChangeLn = { 'GitGutterChangeLine', 'SignifyLineChange', 'DiffChange' }, - GitSignsDeleteLn = { 'GitGutterDeleteLine', 'SignifyLineDelete', 'DiffDelete' }, + { GitSignsAddLn = { 'GitGutterAddLine', 'SignifyLineAdd', 'DiffAdd' } }, + { GitSignsChangeLn = { 'GitGutterChangeLine', 'SignifyLineChange', 'DiffChange' } }, + { GitSignsDeleteLn = { 'GitGutterDeleteLine', 'SignifyLineDelete', 'DiffDelete' } }, - GitSignsCurrentLineBlame = { 'NonText' }, + { GitSignsCurrentLineBlame = { 'NonText' } }, + + { GitSignsAddInline = { 'TermCursor' } }, + { GitSignsDeleteInline = { 'TermCursor' } }, + { GitSignsChangeInline = { 'TermCursor' } }, + + { GitSignsAddLnInline = { 'GitSignsAddInline' } }, + { GitSignsChangeLnInline = { 'GitSignsChangeInline' } }, + { GitSignsDeleteLnInline = { 'GitSignsDeleteInline' } }, + + { GitSignsAddLnVirtLn = { 'GitSignsAddLn' } }, + { GitSignsChangeVirtLn = { 'GitSignsChangeLn' } }, + { GitSignsDeleteVirtLn = { 'GitSignsDeleteLn' } }, + + { GitSignsAddLnVirtLnInLine = { 'GitSignsAddLnInline' } }, + { GitSignsChangeVirtLnInLine = { 'GitSignsChangeLnInline' } }, + { GitSignsDeleteVirtLnInLine = { 'GitSignsDeleteLnInline' } }, } local function is_hl_set(hl_name) local exists, hl = pcall(api.nvim_get_hl_by_name, hl_name, true) - local color = hl.foreground or hl.background + local color = hl.foreground or hl.background or hl.reverse return exists and color ~= nil end -local function isGitSignHl(hl) - return hls[hl] ~= nil -end +M.setup_highlights = function() + for _, hlg in ipairs(hls) do + for hl, candidates in pairs(hlg) do + if is_hl_set(hl) then -M.setup_highlight = function(hl_name) - if not isGitSignHl(hl_name) then - return - end - - if is_hl_set(hl_name) then - - dprintf('Highlight %s is already defined', hl_name) - return - end - - for _, d in ipairs(hls[hl_name]) do - if is_hl_set(d) then - dprintf('Deriving %s from %s', hl_name, d) - vim.cmd(('highlight default link %s %s'):format(hl_name, d)) - return + dprintf('Highlight %s is already defined', hl) + else + for _, d in ipairs(candidates) do + if is_hl_set(d) then + dprintf('Deriving %s from %s', hl, d) + vim.cmd(('highlight default link %s %s'):format(hl, d)) + break + end + end + end end end - - dprintf('Unable to setup highlight %s', hl_name) end return M diff --git a/lua/gitsigns/manager.lua b/lua/gitsigns/manager.lua index 965d43a..07dd17f 100644 --- a/lua/gitsigns/manager.lua +++ b/lua/gitsigns/manager.lua @@ -22,8 +22,7 @@ local util = require('gitsigns.util') local gs_hunks = require("gitsigns.hunks") local Hunk = gs_hunks.Hunk -local setup_highlight = require('gitsigns.highlight').setup_highlight - +local setup_highlights = require('gitsigns.highlight').setup_highlights local config = require('gitsigns.config').config local api = vim.api @@ -184,7 +183,8 @@ 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.added.lines + #hunk.removed.lines) / 2 - local regions = require('gitsigns.diff_int').run_word_diff(hunk.removed.lines, hunk.added.lines) + 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 @@ -199,10 +199,11 @@ M.apply_word_diff = function(bufnr, row) end api.nvim_buf_set_extmark(bufnr, ns, row, scol - 1, { end_col = ecol - 1, - hl_group = rtype == 'add' and 'GitSignsAddLn' or - rtype == 'change' and 'GitSignsChangeLn' or - 'GitSignsDeleteLn', + hl_group = rtype == 'add' and 'GitSignsAddLnInline' or + rtype == 'change' and 'GitSignsChangeLnInline' or + 'GitSignsDeleteLnInline', ephemeral = true, + priority = 1000, }) end end @@ -249,19 +250,19 @@ local function show_deleted(bufnr) if rline > 1 then break end - vline[#vline + 1] = { line:sub(last_ecol, scol - 1), config.signs.delete.linehl } - vline[#vline + 1] = { line:sub(scol, ecol - 1), 'TermCursor' } + vline[#vline + 1] = { line:sub(last_ecol, scol - 1), 'GitsignsDeleteVirtLn' } + vline[#vline + 1] = { line:sub(scol, ecol - 1), 'GitsignsDeleteVirtLnInline' } last_ecol = ecol end end if #line > 0 then - vline[#vline + 1] = { line:sub(last_ecol, -1), config.signs.delete.linehl } + vline[#vline + 1] = { line:sub(last_ecol, -1), 'GitsignsDeleteVirtLn' } end local padding = string.rep(' ', VIRT_LINE_LEN - #line) - vline[#vline + 1] = { padding, config.signs.delete.linehl } + vline[#vline + 1] = { padding, 'GitsignsDeleteVirtLn' } virt_lines[i] = vline end @@ -340,16 +341,6 @@ M.setup_signs_and_highlights = function(redefine) for t, sign_name in pairs(signs.sign_map) do local cs = config.signs[t] - setup_highlight(cs.hl) - - if config.numhl then - setup_highlight(cs.numhl) - end - - if config.linehl or config.word_diff then - setup_highlight(cs.linehl) - end - signs.define(sign_name, { texthl = cs.hl, text = config.signcolumn and cs.text or nil, @@ -358,9 +349,8 @@ M.setup_signs_and_highlights = function(redefine) }, redefine) end - if config.current_line_blame then - setup_highlight('GitSignsCurrentLineBlame') - end + + setup_highlights() end return M diff --git a/teal/gitsigns/actions.tl b/teal/gitsigns/actions.tl index 530768d..b99409b 100644 --- a/teal/gitsigns/actions.tl +++ b/teal/gitsigns/actions.tl @@ -21,6 +21,7 @@ local Hunk_Public = gs_hunks.Hunk_Public local api = vim.api local current_buf = api.nvim_get_current_buf +local add_highlight = api.nvim_buf_add_highlight local record NavHunkOpts forwards: boolean @@ -437,17 +438,21 @@ end local function highlight_hunk_lines(bufnr: integer, offset: integer, hunk: Hunk) for i = 1, #hunk.removed.lines do - api.nvim_buf_add_highlight(bufnr, -1, 'DiffRemoved', offset+i-1, 0, -1) + add_highlight(bufnr, -1, 'GitSignsDeleteLn', offset+i-1, 0, -1) end for i = 1, #hunk.added.lines do - api.nvim_buf_add_highlight(bufnr, -1, 'DiffAdded', #hunk.removed.lines + offset+i-1, 0, -1) + add_highlight(bufnr, -1, 'GitSignsAddLn', #hunk.removed.lines + offset+i-1, 0, -1) end if config.diff_opts.internal then - local regions = require('gitsigns.diff_int').run_word_diff(hunk.removed.lines, hunk.added.lines) - for _, region in ipairs(regions) do + local removed_regions, added_regions = require('gitsigns.diff_int').run_word_diff(hunk.removed.lines, hunk.added.lines) + for _, region in ipairs(removed_regions) do local line, scol, ecol = region[1], region[3], region[4] - api.nvim_buf_add_highlight(bufnr, -1, 'TermCursor', line+offset-1, scol, ecol) + add_highlight(bufnr, -1, 'GitSignsDeleteInline', line+offset-1, scol, ecol) + end + for _, region in ipairs(added_regions) do + local line, scol, ecol = region[1], region[3], region[4] + add_highlight(bufnr, -1, 'GitSignsAddInline', line+offset-1, scol, ecol) end end end @@ -499,7 +504,7 @@ M.preview_hunk = noautocmd(function() local _, bufnr = popup.create(lines, config.preview_config) - api.nvim_buf_add_highlight(bufnr, -1, 'Title', 0, 0, -1) + add_highlight(bufnr, -1, 'Title', 0, 0, -1) api.nvim_buf_set_var(cbuf, '_gitsigns_preview_open', true) vim.cmd[[autocmd CursorMoved,CursorMovedI ++once silent! unlet b:_gitsigns_preview_open]] @@ -637,7 +642,7 @@ M.blame_line = void(function(opts: boolean | BlameOpts) local highlights: {{string, integer, integer, integer}} = {} - local function add_highlight(hlgroup: string, start: integer, length: integer) + local function add_hl(hlgroup: string, start: integer, length: integer) highlights[#highlights+1] = {hlgroup, #lines-1, start or 0, length or -1} end @@ -660,9 +665,9 @@ M.blame_line = void(function(opts: boolean | BlameOpts) local p2 = #result.author local p3 = #date - add_highlight('Directory', 0 , p1) - add_highlight('MoreMsg' , p1+1 , p2) - add_highlight('Label' , p1+p2+2, p3+2) + add_hl('Directory', 0 , p1) + add_hl('MoreMsg' , p1+1 , p2) + add_hl('Label' , p1+p2+2, p3+2) vim.list_extend(lines, commit_message) @@ -671,7 +676,7 @@ M.blame_line = void(function(opts: boolean | BlameOpts) end else lines[#lines+1] = result.author - add_highlight('ErrorMsg') + add_hl('ErrorMsg') if full then scheduler() hunk, ihunk = get_cursor_hunk(bufnr, bcache.hunks) @@ -682,7 +687,7 @@ M.blame_line = void(function(opts: boolean | BlameOpts) if hunk then lines[#lines+1] = '' lines[#lines+1] = ('Hunk %d of %d'):format(ihunk, nhunk) - add_highlight('Title') + add_hl('Title') vim.list_extend(lines, gs_hunks.patch_lines(hunk)) end @@ -691,7 +696,7 @@ M.blame_line = void(function(opts: boolean | BlameOpts) for _, h in ipairs(highlights) do local hlgroup, line, start, length = h[1], h[2], h[3], h[4] - api.nvim_buf_add_highlight(pbufnr, -1, hlgroup, line, start, start+length) + add_highlight(pbufnr, -1, hlgroup, line, start, start+length) end if hunk then diff --git a/teal/gitsigns/config.tl b/teal/gitsigns/config.tl index 19f7ea1..573b6f3 100644 --- a/teal/gitsigns/config.tl +++ b/teal/gitsigns/config.tl @@ -131,18 +131,16 @@ M.schema = { • `show_count` to enable showing count of hunk, e.g. number of deleted lines. - Note if `hl`, `numhl` or `linehl` use a `GitSigns*` highlight and it is - not defined, it will be automatically derived by searching for other - defined highlights in the following order: + Note if a highlight is not defined, it will be automatically derived by + searching for other defined highlights in the following order: • `GitGutter*` • `Signify*` • `Diff*Gutter` • `diff*` • `Diff*` - For example if `signs.add.hl = GitSignsAdd` and `GitSignsAdd` is not - defined but `GitGutterAdd` is defined, then `GitSignsAdd` will be linked - to `GitGutterAdd`. + For example if `GitSignsAdd` is not defined but `GitGutterAdd` is defined, + then `GitSignsAdd` will be linked to `GitGutterAdd`. ]] }, @@ -591,9 +589,18 @@ M.schema = { Requires `config.diff_opts.internal = true` . Uses the highlights: - • GitSignsAddLn - • GitSignsChangeLn - • GitSignsDeleteLn + • For word diff in previews: + • `GitSignsAddInline` + • `GitSignsChangeInline` + • `GitSignsDeleteInline` + • For word diff in buffer: + • `GitSignsAddLnInline` + • `GitSignsChangeLnInline` + • `GitSignsDeleteLnInline` + • For word diff in virtual lines (e.g. show_deleted): + • `GitSignsAddVirtLnInline` + • `GitSignsChangeVirtLnInline` + • `GitSignsDeleteVirtLnInline` ]] }, diff --git a/teal/gitsigns/diff_int.tl b/teal/gitsigns/diff_int.tl index 90b9500..4808636 100644 --- a/teal/gitsigns/diff_int.tl +++ b/teal/gitsigns/diff_int.tl @@ -49,12 +49,13 @@ local type Region = {integer, string, integer, integer} local gaps_between_regions = 5 -function M.run_word_diff(removed: {string}, added: {string}): {Region} - if #removed ~= #added then - return {} - end +function M.run_word_diff(removed: {string}, added: {string}): {Region}, {Region} + local adds: {Region} = {} + local rems: {Region} = {} - local ret: {Region} = {} + if #removed ~= #added then + return rems, adds + end for i = 1, #removed do -- pair lines by position @@ -93,14 +94,11 @@ function M.run_word_diff(removed: {string}, added: {string}): {Region} 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 + adds[#adds+1] = {i+#removed, h.type, h.added.start , h.added.start + h.added.count} + rems[#rems+1] = {i , h.type, h.removed.start, h.removed.start + h.removed.count} end end - return ret + return rems, adds end return M diff --git a/teal/gitsigns/highlight.tl b/teal/gitsigns/highlight.tl index ad287aa..600ad4c 100644 --- a/teal/gitsigns/highlight.tl +++ b/teal/gitsigns/highlight.tl @@ -4,74 +4,68 @@ local api = vim.api local dprintf = require("gitsigns.debug").dprintf local record M - setup_highlight: function(string) + setup_highlights: function() end -local enum GitSignHl - 'GitSignsAdd' - 'GitSignsChange' - 'GitSignsDelete' +-- Use array of dict so we can iterate deterministically +local hls: {{string:{string}}} = { + {GitSignsAdd = {'GitGutterAdd' , 'SignifySignAdd' , 'DiffAddedGutter' , 'diffAdded' , 'DiffAdd' }}, + {GitSignsChange = {'GitGutterChange', 'SignifySignChange', 'DiffModifiedGutter', 'diffChanged', 'DiffChange'}}, + {GitSignsDelete = {'GitGutterDelete', 'SignifySignDelete', 'DiffRemovedGutter' , 'diffRemoved', 'DiffDelete'}}, - 'GitSignsAddNr' - 'GitSignsChangeNr' - 'GitSignsDeleteNr' + {GitSignsAddNr = {'GitGutterAddLineNr' , 'GitSignsAdd' }}, + {GitSignsChangeNr = {'GitGutterChangeLineNr', 'GitSignsChange'}}, + {GitSignsDeleteNr = {'GitGutterDeleteLineNr', 'GitSignsDelete'}}, - 'GitSignsAddLn' - 'GitSignsChangeLn' - 'GitSignsDeleteLn' + {GitSignsAddLn = {'GitGutterAddLine' , 'SignifyLineAdd' , 'DiffAdd' }}, + {GitSignsChangeLn = {'GitGutterChangeLine', 'SignifyLineChange', 'DiffChange'}}, + {GitSignsDeleteLn = {'GitGutterDeleteLine', 'SignifyLineDelete', 'DiffDelete'}}, - 'GitSignsCurrentLineBlame' -end + {GitSignsCurrentLineBlame = {'NonText'}}, -local hls: {GitSignHl:{string}} = { - GitSignsAdd = {'GitGutterAdd' , 'SignifySignAdd' , 'DiffAddedGutter' , 'diffAdded' , 'DiffAdd' }, - GitSignsChange = {'GitGutterChange', 'SignifySignChange', 'DiffModifiedGutter', 'diffChanged', 'DiffChange'}, - GitSignsDelete = {'GitGutterDelete', 'SignifySignDelete', 'DiffRemovedGutter' , 'diffRemoved', 'DiffDelete'}, + {GitSignsAddInline = {'TermCursor'}}, + {GitSignsDeleteInline = {'TermCursor'}}, + {GitSignsChangeInline = {'TermCursor'}}, - GitSignsAddNr = {'GitGutterAddLineNr' , 'GitSignsAdd' , 'SignifySignAdd' , 'DiffAddedGutter' , 'diffAdded' , 'DiffAdd' }, - GitSignsChangeNr = {'GitGutterChangeLineNr', 'GitSignsChange', 'SignifySignChange', 'DiffModifiedGutter', 'diffChanged', 'DiffChange'}, - GitSignsDeleteNr = {'GitGutterDeleteLineNr', 'GitSignsDelete', 'SignifySignDelete', 'DiffRemovedGutter' , 'diffRemoved', 'DiffDelete'}, + {GitSignsAddLnInline = {'GitSignsAddInline'}}, + {GitSignsChangeLnInline = {'GitSignsChangeInline'}}, + {GitSignsDeleteLnInline = {'GitSignsDeleteInline'}}, - GitSignsAddLn = {'GitGutterAddLine' , 'SignifyLineAdd' , 'DiffAdd' }, - GitSignsChangeLn = {'GitGutterChangeLine', 'SignifyLineChange', 'DiffChange'}, - GitSignsDeleteLn = {'GitGutterDeleteLine', 'SignifyLineDelete', 'DiffDelete'}, + {GitSignsAddLnVirtLn = {'GitSignsAddLn' }}, + {GitSignsChangeVirtLn = {'GitSignsChangeLn'}}, + {GitSignsDeleteVirtLn = {'GitSignsDeleteLn'}}, - GitSignsCurrentLineBlame = {'NonText'}, + {GitSignsAddLnVirtLnInLine = {'GitSignsAddLnInline' }}, + {GitSignsChangeVirtLnInLine = {'GitSignsChangeLnInline'}}, + {GitSignsDeleteVirtLnInLine = {'GitSignsDeleteLnInline'}}, } local function is_hl_set(hl_name: string): boolean -- TODO: this only works with `set termguicolors` local exists, hl = pcall(api.nvim_get_hl_by_name, hl_name, true) - local color = hl.foreground or hl.background + local color = hl.foreground or hl.background or hl.reverse return exists and color ~= nil end -local function isGitSignHl(hl: string): boolean - return hls[hl as GitSignHl] ~= nil -end - -- Setup a GitSign* highlight by deriving it from other potentially present -- highlights. -M.setup_highlight = function(hl_name: string) - if not isGitSignHl(hl_name) then - return - end - - if is_hl_set(hl_name) then - -- Already defined - dprintf('Highlight %s is already defined', hl_name) - return - end - - for _, d in ipairs(hls[hl_name as GitSignHl]) do - if is_hl_set(d) then - dprintf('Deriving %s from %s', hl_name, d) - vim.cmd(('highlight default link %s %s'):format(hl_name, d)) - return +M.setup_highlights = function() + for _, hlg in ipairs(hls) do + for hl, candidates in pairs(hlg) do + if is_hl_set(hl) then + -- Already defined + dprintf('Highlight %s is already defined', hl) + else + for _, d in ipairs(candidates) do + if is_hl_set(d) then + dprintf('Deriving %s from %s', hl, d) + vim.cmd(('highlight default link %s %s'):format(hl, d)) + break + end + end + end end end - - dprintf('Unable to setup highlight %s', hl_name) end return M diff --git a/teal/gitsigns/manager.tl b/teal/gitsigns/manager.tl index 8dbcbc0..34b825b 100644 --- a/teal/gitsigns/manager.tl +++ b/teal/gitsigns/manager.tl @@ -22,9 +22,8 @@ local util = require('gitsigns.util') 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 +local setup_highlights = require('gitsigns.highlight').setup_highlights +local config = require('gitsigns.config').config local api = vim.api @@ -184,7 +183,8 @@ 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.added.lines +#hunk.removed.lines) / 2 - local regions = require('gitsigns.diff_int').run_word_diff(hunk.removed.lines, hunk.added.lines) + 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 @@ -199,10 +199,11 @@ M.apply_word_diff = function(bufnr: integer, row: integer) end api.nvim_buf_set_extmark(bufnr, ns, row, scol-1, { end_col = ecol-1, - hl_group = rtype == 'add' and 'GitSignsAddLn' - or rtype == 'change' and 'GitSignsChangeLn' - or 'GitSignsDeleteLn', - ephemeral = true + hl_group = rtype == 'add' and 'GitSignsAddLnInline' + or rtype == 'change' and 'GitSignsChangeLnInline' + or 'GitSignsDeleteLnInline', + ephemeral = true, + priority = 1000 }) end end @@ -249,19 +250,19 @@ local function show_deleted(bufnr: integer) if rline > 1 then break end - vline[#vline+1] = { line:sub(last_ecol, scol-1), config.signs.delete.linehl } - vline[#vline+1] = { line:sub(scol, ecol-1), 'TermCursor'} + vline[#vline+1] = { line:sub(last_ecol, scol-1), 'GitsignsDeleteVirtLn'} + vline[#vline+1] = { line:sub(scol, ecol-1), 'GitsignsDeleteVirtLnInline'} last_ecol = ecol end end if #line > 0 then - vline[#vline+1] = { line:sub(last_ecol, -1), config.signs.delete.linehl } + vline[#vline+1] = { line:sub(last_ecol, -1), 'GitsignsDeleteVirtLn'} end -- Add extra padding so the entire line is highlighted local padding = string.rep(' ', VIRT_LINE_LEN-#line) - vline[#vline+1] = { padding, config.signs.delete.linehl } + vline[#vline+1] = { padding, 'GitsignsDeleteVirtLn'} virt_lines[i] = vline end @@ -340,16 +341,6 @@ M.setup_signs_and_highlights = function(redefine: boolean) for t, sign_name in pairs(signs.sign_map) do local cs = config.signs[t] - setup_highlight(cs.hl) - - if config.numhl then - setup_highlight(cs.numhl) - end - - if config.linehl or config.word_diff then - setup_highlight(cs.linehl) - end - signs.define(sign_name, { texthl = cs.hl, text = config.signcolumn and cs.text or nil, @@ -358,9 +349,8 @@ M.setup_signs_and_highlights = function(redefine: boolean) }, redefine) end - if config.current_line_blame then - setup_highlight('GitSignsCurrentLineBlame') - end + + setup_highlights() end return M diff --git a/test/gitdir_watcher_spec.lua b/test/gitdir_watcher_spec.lua index 66116dc..7f50fc7 100644 --- a/test/gitdir_watcher_spec.lua +++ b/test/gitdir_watcher_spec.lua @@ -33,11 +33,10 @@ describe('gitdir_watcher', function() it('can follow moved files', function() setup_test_repo() setup_gitsigns(test_config) + command('Gitsigns clear_debug') edit(test_file) match_debug_messages { - "run_job: git --no-pager --version", - 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', 'attach(1): Attaching (trigger=BufRead)', p"run_job: git .* config user.name", "run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD", diff --git a/test/gitsigns_spec.lua b/test/gitsigns_spec.lua index 13c7ea6..495d081 100644 --- a/test/gitsigns_spec.lua +++ b/test/gitsigns_spec.lua @@ -107,12 +107,11 @@ describe('gitsigns', function() it('can open files not in a git repo', function() setup_gitsigns(config) + command('Gitsigns clear_debug') local tmpfile = os.tmpname() edit(tmpfile) match_debug_messages { - 'run_job: git --no-pager --version', - 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', 'attach(1): Attaching (trigger=BufRead)', p'run_job: git .* config user.name', 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', @@ -158,11 +157,10 @@ describe('gitsigns', function() end) it('does not attach inside .git', function() + command("Gitsigns clear_debug") edit(scratch..'/.git/index') match_debug_messages { - 'run_job: git --no-pager --version', - 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', 'attach(1): Attaching (trigger=BufRead)', 'new: In git dir', 'attach(1): Empty git obj' @@ -170,6 +168,7 @@ describe('gitsigns', function() end) it('doesn\'t attach to ignored files', function() + command("Gitsigns clear_debug") write_to_file(scratch..'/.gitignore', {'dummy_ignored.txt'}) local ignored_file = scratch.."/dummy_ignored.txt" @@ -178,8 +177,6 @@ describe('gitsigns', function() edit(ignored_file) match_debug_messages { - 'run_job: git --no-pager --version', - 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', 'attach(1): Attaching (trigger=BufRead)', p'run_job: git .* config user.name', 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', @@ -191,11 +188,10 @@ describe('gitsigns', function() end) it('doesn\'t attach to non-existent files', function() + command("Gitsigns clear_debug") edit(newfile) match_debug_messages { - 'run_job: git --no-pager --version', - 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', 'attach(1): Attaching (trigger=BufNewFile)', p'run_job: git .* config user.name', 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', @@ -207,11 +203,10 @@ describe('gitsigns', function() end) it('doesn\'t attach to non-existent files with non-existent sub-dirs', function() + command("Gitsigns clear_debug") edit(scratch..'/does/not/exist') match_debug_messages { - 'run_job: git --no-pager --version', - 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', 'attach(1): Attaching (trigger=BufNewFile)', 'attach(1): Not a path', } @@ -221,10 +216,9 @@ describe('gitsigns', function() end) it('can run copen', function() + command("Gitsigns clear_debug") command("copen") match_debug_messages { - 'run_job: git --no-pager --version', - 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', 'attach(2): Attaching (trigger=BufRead)', 'attach(2): Non-normal buffer', } @@ -340,11 +334,10 @@ describe('gitsigns', function() return false end ]]) + command("Gitsigns clear_debug") edit(test_file) match_debug_messages { - 'run_job: git --no-pager --version', - 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', 'attach(1): Attaching (trigger=BufRead)', p'run_job: git .* config user.name', 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', @@ -455,10 +448,9 @@ describe('gitsigns', function() it('attaches to newly created files', function() setup_gitsigns(config) + command('Gitsigns clear_debug') edit(newfile) match_debug_messages{ - 'run_job: git --no-pager --version', - 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', 'attach(1): Attaching (trigger=BufNewFile)', 'run_job: git --no-pager config user.name', 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', @@ -656,6 +648,7 @@ describe('gitsigns', function() write_to_file(scratch..'/t3.txt', {'hello lewis'}) setup_gitsigns(config) + command('Gitsigns clear_debug') helpers.exc_exec("vimgrep ben "..scratch..'/*') @@ -664,8 +657,6 @@ describe('gitsigns', function() }}} eq({ - 'run_job: git --no-pager --version', - 'run_job: git --no-pager rev-parse --show-toplevel --absolute-git-dir --abbrev-ref HEAD', 'attach(2): attaching is disabled', 'attach(3): attaching is disabled', 'attach(4): attaching is disabled', diff --git a/types/types.d.tl b/types/types.d.tl index b1d1c65..d6ddbc5 100644 --- a/types/types.d.tl +++ b/types/types.d.tl @@ -384,7 +384,7 @@ global record vim in_fast_event: function(): boolean - list_extend: function({any}, {any}, integer, integer) + list_extend: function({T}, {T}, integer, integer): {T} list_slice: function({T}, integer, integer): {T} record keymap