commit
6c4c1e8e49
6 changed files with 110 additions and 58 deletions
|
|
@ -56,7 +56,7 @@ CONFIGURATION *fugitive-ts-config*
|
||||||
Example: >lua
|
Example: >lua
|
||||||
disabled_languages = { 'markdown', 'text' }
|
disabled_languages = { 'markdown', 'text' }
|
||||||
<
|
<
|
||||||
{debounce_ms} (integer, default: 50)
|
{debounce_ms} (integer, default: 0)
|
||||||
Debounce delay in milliseconds for re-highlighting
|
Debounce delay in milliseconds for re-highlighting
|
||||||
after buffer changes. Lower values feel snappier
|
after buffer changes. Lower values feel snappier
|
||||||
but use more CPU.
|
but use more CPU.
|
||||||
|
|
@ -65,7 +65,7 @@ CONFIGURATION *fugitive-ts-config*
|
||||||
Skip treesitter highlighting for hunks larger than
|
Skip treesitter highlighting for hunks larger than
|
||||||
this many lines. Prevents lag on massive diffs.
|
this many lines. Prevents lag on massive diffs.
|
||||||
|
|
||||||
{conceal_prefixes} (boolean, default: true)
|
{hide_prefix} (boolean, default: true)
|
||||||
Hide diff prefixes (`+`/`-`/` `) using virtual
|
Hide diff prefixes (`+`/`-`/` `) using virtual
|
||||||
text overlay. Makes code appear without the
|
text overlay. Makes code appear without the
|
||||||
leading diff character. When `highlights.background`
|
leading diff character. When `highlights.background`
|
||||||
|
|
@ -133,7 +133,7 @@ IMPLEMENTATION *fugitive-ts-implementation*
|
||||||
- Background extmarks (`FugitiveTsAdd`/`FugitiveTsDelete`) at priority 198
|
- Background extmarks (`FugitiveTsAdd`/`FugitiveTsDelete`) at priority 198
|
||||||
- `Normal` extmarks at priority 199 clear underlying diff foreground
|
- `Normal` extmarks at priority 199 clear underlying diff foreground
|
||||||
- Treesitter highlights are applied as extmarks at priority 200
|
- Treesitter highlights are applied as extmarks at priority 200
|
||||||
- Virtual text overlays hide diff prefixes when `conceal_prefixes` is enabled
|
- Conceal extmarks hide diff prefixes when `hide_prefix` is enabled
|
||||||
4. Re-highlighting occurs on `TextChanged` (debounced) and `Syntax` events
|
4. Re-highlighting occurs on `TextChanged` (debounced) and `Syntax` events
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ end
|
||||||
|
|
||||||
---@class fugitive-ts.HunkOpts
|
---@class fugitive-ts.HunkOpts
|
||||||
---@field max_lines integer
|
---@field max_lines integer
|
||||||
---@field conceal_prefixes boolean
|
---@field hide_prefix boolean
|
||||||
---@field highlights fugitive-ts.Highlights
|
---@field highlights fugitive-ts.Highlights
|
||||||
|
|
||||||
---@param bufnr integer
|
---@param bufnr integer
|
||||||
|
|
@ -90,6 +90,49 @@ function M.highlight_hunk(bufnr, ns, hunk, opts)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
for i, line in ipairs(hunk.lines) do
|
||||||
|
local buf_line = hunk.start_line + i - 1
|
||||||
|
local line_len = #line
|
||||||
|
local prefix = line:sub(1, 1)
|
||||||
|
|
||||||
|
local is_diff_line = prefix == '+' or prefix == '-'
|
||||||
|
local line_hl = is_diff_line and (prefix == '+' and 'FugitiveTsAdd' or 'FugitiveTsDelete')
|
||||||
|
or nil
|
||||||
|
local number_hl = is_diff_line and (prefix == '+' and 'FugitiveTsAddNr' or 'FugitiveTsDeleteNr')
|
||||||
|
or nil
|
||||||
|
|
||||||
|
if opts.hide_prefix then
|
||||||
|
local virt_hl = (opts.highlights.background and line_hl) or nil
|
||||||
|
pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, buf_line, 0, {
|
||||||
|
virt_text = { { ' ', virt_hl } },
|
||||||
|
virt_text_pos = 'overlay',
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if opts.highlights.background and is_diff_line then
|
||||||
|
local extmark_opts = {
|
||||||
|
line_hl_group = line_hl,
|
||||||
|
priority = 198,
|
||||||
|
}
|
||||||
|
if opts.highlights.gutter then
|
||||||
|
extmark_opts.number_hl_group = number_hl
|
||||||
|
end
|
||||||
|
pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, buf_line, 0, extmark_opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
if line_len > 1 and opts.highlights.treesitter then
|
||||||
|
pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, buf_line, 1, {
|
||||||
|
end_col = line_len,
|
||||||
|
hl_group = 'Normal',
|
||||||
|
priority = 199,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not opts.highlights.treesitter then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
---@type string[]
|
---@type string[]
|
||||||
local code_lines = {}
|
local code_lines = {}
|
||||||
for _, line in ipairs(hunk.lines) do
|
for _, line in ipairs(hunk.lines) do
|
||||||
|
|
@ -133,47 +176,6 @@ function M.highlight_hunk(bufnr, ns, hunk, opts)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for i, line in ipairs(hunk.lines) do
|
|
||||||
local buf_line = hunk.start_line + i - 1
|
|
||||||
local line_len = #line
|
|
||||||
local prefix = line:sub(1, 1)
|
|
||||||
|
|
||||||
local is_diff_line = prefix == '+' or prefix == '-'
|
|
||||||
local line_hl = is_diff_line and (prefix == '+' and 'FugitiveTsAdd' or 'FugitiveTsDelete')
|
|
||||||
or nil
|
|
||||||
|
|
||||||
if opts.conceal_prefixes then
|
|
||||||
local virt_hl = (opts.highlights.background and line_hl) or nil
|
|
||||||
pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, buf_line, 0, {
|
|
||||||
virt_text = { { ' ', virt_hl } },
|
|
||||||
virt_text_pos = 'overlay',
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
if opts.highlights.background and is_diff_line then
|
|
||||||
local extmark_opts = {
|
|
||||||
line_hl_group = line_hl,
|
|
||||||
priority = 198,
|
|
||||||
}
|
|
||||||
if opts.highlights.gutter then
|
|
||||||
extmark_opts.number_hl_group = line_hl
|
|
||||||
end
|
|
||||||
pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, buf_line, 0, extmark_opts)
|
|
||||||
end
|
|
||||||
|
|
||||||
if line_len > 1 and opts.highlights.treesitter then
|
|
||||||
pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, buf_line, 1, {
|
|
||||||
end_col = line_len,
|
|
||||||
hl_group = 'Normal',
|
|
||||||
priority = 199,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not opts.highlights.treesitter then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local extmark_count = 0
|
local extmark_count = 0
|
||||||
for id, node, _ in query:iter_captures(trees[1]:root(), code) do
|
for id, node, _ in query:iter_captures(trees[1]:root(), code) do
|
||||||
local capture_name = '@' .. query.captures[id]
|
local capture_name = '@' .. query.captures[id]
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
---@field disabled_languages string[]
|
---@field disabled_languages string[]
|
||||||
---@field debounce_ms integer
|
---@field debounce_ms integer
|
||||||
---@field max_lines_per_hunk integer
|
---@field max_lines_per_hunk integer
|
||||||
---@field conceal_prefixes boolean
|
---@field hide_prefix boolean
|
||||||
---@field highlights fugitive-ts.Highlights
|
---@field highlights fugitive-ts.Highlights
|
||||||
|
|
||||||
---@class fugitive-ts
|
---@class fugitive-ts
|
||||||
|
|
@ -25,15 +25,47 @@ local parser = require('fugitive-ts.parser')
|
||||||
|
|
||||||
local ns = vim.api.nvim_create_namespace('fugitive_ts')
|
local ns = vim.api.nvim_create_namespace('fugitive_ts')
|
||||||
|
|
||||||
|
---@param hex integer
|
||||||
|
---@param bg_hex integer
|
||||||
|
---@param alpha number
|
||||||
|
---@return integer
|
||||||
|
local function blend_color(hex, bg_hex, alpha)
|
||||||
|
---@diagnostic disable: undefined-global
|
||||||
|
local r = bit.band(bit.rshift(hex, 16), 0xFF)
|
||||||
|
local g = bit.band(bit.rshift(hex, 8), 0xFF)
|
||||||
|
local b = bit.band(hex, 0xFF)
|
||||||
|
|
||||||
|
local bg_r = bit.band(bit.rshift(bg_hex, 16), 0xFF)
|
||||||
|
local bg_g = bit.band(bit.rshift(bg_hex, 8), 0xFF)
|
||||||
|
local bg_b = bit.band(bg_hex, 0xFF)
|
||||||
|
|
||||||
|
local blend_r = math.floor(r * alpha + bg_r * (1 - alpha))
|
||||||
|
local blend_g = math.floor(g * alpha + bg_g * (1 - alpha))
|
||||||
|
local blend_b = math.floor(b * alpha + bg_b * (1 - alpha))
|
||||||
|
|
||||||
|
return bit.bor(bit.lshift(blend_r, 16), bit.lshift(blend_g, 8), blend_b)
|
||||||
|
---@diagnostic enable: undefined-global
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param name string
|
||||||
|
---@return table
|
||||||
|
local function resolve_hl(name)
|
||||||
|
local hl = vim.api.nvim_get_hl(0, { name = name })
|
||||||
|
while hl.link do
|
||||||
|
hl = vim.api.nvim_get_hl(0, { name = hl.link })
|
||||||
|
end
|
||||||
|
return hl
|
||||||
|
end
|
||||||
|
|
||||||
---@type fugitive-ts.Config
|
---@type fugitive-ts.Config
|
||||||
local default_config = {
|
local default_config = {
|
||||||
enabled = true,
|
enabled = true,
|
||||||
debug = false,
|
debug = false,
|
||||||
languages = {},
|
languages = {},
|
||||||
disabled_languages = {},
|
disabled_languages = {},
|
||||||
debounce_ms = 50,
|
debounce_ms = 0,
|
||||||
max_lines_per_hunk = 500,
|
max_lines_per_hunk = 500,
|
||||||
conceal_prefixes = true,
|
hide_prefix = false,
|
||||||
highlights = {
|
highlights = {
|
||||||
treesitter = true,
|
treesitter = true,
|
||||||
background = true,
|
background = true,
|
||||||
|
|
@ -75,7 +107,7 @@ local function highlight_buffer(bufnr)
|
||||||
for _, hunk in ipairs(hunks) do
|
for _, hunk in ipairs(hunks) do
|
||||||
highlight.highlight_hunk(bufnr, ns, hunk, {
|
highlight.highlight_hunk(bufnr, ns, hunk, {
|
||||||
max_lines = config.max_lines_per_hunk,
|
max_lines = config.max_lines_per_hunk,
|
||||||
conceal_prefixes = config.conceal_prefixes,
|
hide_prefix = config.hide_prefix,
|
||||||
highlights = config.highlights,
|
highlights = config.highlights,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
@ -164,7 +196,7 @@ function M.setup(opts)
|
||||||
disabled_languages = { opts.disabled_languages, 'table', true },
|
disabled_languages = { opts.disabled_languages, 'table', true },
|
||||||
debounce_ms = { opts.debounce_ms, 'number', true },
|
debounce_ms = { opts.debounce_ms, 'number', true },
|
||||||
max_lines_per_hunk = { opts.max_lines_per_hunk, 'number', true },
|
max_lines_per_hunk = { opts.max_lines_per_hunk, 'number', true },
|
||||||
conceal_prefixes = { opts.conceal_prefixes, 'boolean', true },
|
hide_prefix = { opts.hide_prefix, 'boolean', true },
|
||||||
highlights = { opts.highlights, 'table', true },
|
highlights = { opts.highlights, 'table', true },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -181,10 +213,25 @@ function M.setup(opts)
|
||||||
parser.set_debug(config.debug)
|
parser.set_debug(config.debug)
|
||||||
highlight.set_debug(config.debug)
|
highlight.set_debug(config.debug)
|
||||||
|
|
||||||
|
local normal = vim.api.nvim_get_hl(0, { name = 'Normal' })
|
||||||
local diff_add = vim.api.nvim_get_hl(0, { name = 'DiffAdd' })
|
local diff_add = vim.api.nvim_get_hl(0, { name = 'DiffAdd' })
|
||||||
local diff_delete = vim.api.nvim_get_hl(0, { name = 'DiffDelete' })
|
local diff_delete = vim.api.nvim_get_hl(0, { name = 'DiffDelete' })
|
||||||
vim.api.nvim_set_hl(0, 'FugitiveTsAdd', { bg = diff_add.bg })
|
local diff_added = resolve_hl('diffAdded')
|
||||||
vim.api.nvim_set_hl(0, 'FugitiveTsDelete', { bg = diff_delete.bg })
|
local diff_removed = resolve_hl('diffRemoved')
|
||||||
|
|
||||||
|
local bg = normal.bg or 0x1e1e2e
|
||||||
|
local add_bg = diff_add.bg or 0x2e4a3a
|
||||||
|
local del_bg = diff_delete.bg or 0x4a2e3a
|
||||||
|
local add_fg = diff_added.fg or diff_add.fg or 0x80c080
|
||||||
|
local del_fg = diff_removed.fg or diff_delete.fg or 0xc08080
|
||||||
|
|
||||||
|
local blended_add = blend_color(add_bg, bg, 0.4)
|
||||||
|
local blended_del = blend_color(del_bg, bg, 0.4)
|
||||||
|
|
||||||
|
vim.api.nvim_set_hl(0, 'FugitiveTsAdd', { bg = blended_add })
|
||||||
|
vim.api.nvim_set_hl(0, 'FugitiveTsDelete', { bg = blended_del })
|
||||||
|
vim.api.nvim_set_hl(0, 'FugitiveTsAddNr', { fg = add_fg, bg = blended_add })
|
||||||
|
vim.api.nvim_set_hl(0, 'FugitiveTsDeleteNr', { fg = del_fg, bg = blended_del })
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ describe('highlight', function()
|
||||||
local function default_opts(overrides)
|
local function default_opts(overrides)
|
||||||
local opts = {
|
local opts = {
|
||||||
max_lines = 500,
|
max_lines = 500,
|
||||||
conceal_prefixes = false,
|
hide_prefix = false,
|
||||||
highlights = {
|
highlights = {
|
||||||
treesitter = true,
|
treesitter = true,
|
||||||
background = false,
|
background = false,
|
||||||
|
|
@ -241,7 +241,7 @@ describe('highlight', function()
|
||||||
delete_buffer(bufnr)
|
delete_buffer(bufnr)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('applies overlay extmarks when conceal_prefixes enabled', function()
|
it('applies overlay extmarks when hide_prefix enabled', function()
|
||||||
local bufnr = create_buffer({
|
local bufnr = create_buffer({
|
||||||
'@@ -1,1 +1,2 @@',
|
'@@ -1,1 +1,2 @@',
|
||||||
' local x = 1',
|
' local x = 1',
|
||||||
|
|
@ -255,7 +255,7 @@ describe('highlight', function()
|
||||||
lines = { ' local x = 1', '+local y = 2' },
|
lines = { ' local x = 1', '+local y = 2' },
|
||||||
}
|
}
|
||||||
|
|
||||||
highlight.highlight_hunk(bufnr, ns, hunk, default_opts({ conceal_prefixes = true }))
|
highlight.highlight_hunk(bufnr, ns, hunk, default_opts({ hide_prefix = true }))
|
||||||
|
|
||||||
local extmarks = get_extmarks(bufnr)
|
local extmarks = get_extmarks(bufnr)
|
||||||
local overlay_count = 0
|
local overlay_count = 0
|
||||||
|
|
@ -268,7 +268,7 @@ describe('highlight', function()
|
||||||
delete_buffer(bufnr)
|
delete_buffer(bufnr)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('does not apply overlay extmarks when conceal_prefixes disabled', function()
|
it('does not apply overlay extmarks when hide_prefix disabled', function()
|
||||||
local bufnr = create_buffer({
|
local bufnr = create_buffer({
|
||||||
'@@ -1,1 +1,2 @@',
|
'@@ -1,1 +1,2 @@',
|
||||||
' local x = 1',
|
' local x = 1',
|
||||||
|
|
@ -282,7 +282,7 @@ describe('highlight', function()
|
||||||
lines = { ' local x = 1', '+local y = 2' },
|
lines = { ' local x = 1', '+local y = 2' },
|
||||||
}
|
}
|
||||||
|
|
||||||
highlight.highlight_hunk(bufnr, ns, hunk, default_opts({ conceal_prefixes = false }))
|
highlight.highlight_hunk(bufnr, ns, hunk, default_opts({ hide_prefix = false }))
|
||||||
|
|
||||||
local extmarks = get_extmarks(bufnr)
|
local extmarks = get_extmarks(bufnr)
|
||||||
local overlay_count = 0
|
local overlay_count = 0
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ describe('fugitive-ts', function()
|
||||||
disabled_languages = { 'markdown' },
|
disabled_languages = { 'markdown' },
|
||||||
debounce_ms = 100,
|
debounce_ms = 100,
|
||||||
max_lines_per_hunk = 1000,
|
max_lines_per_hunk = 1000,
|
||||||
conceal_prefixes = false,
|
hide_prefix = false,
|
||||||
highlights = {
|
highlights = {
|
||||||
treesitter = true,
|
treesitter = true,
|
||||||
background = true,
|
background = true,
|
||||||
|
|
|
||||||
3
vim.toml
3
vim.toml
|
|
@ -8,6 +8,9 @@ any = true
|
||||||
[jit]
|
[jit]
|
||||||
any = true
|
any = true
|
||||||
|
|
||||||
|
[bit]
|
||||||
|
any = true
|
||||||
|
|
||||||
[assert]
|
[assert]
|
||||||
any = true
|
any = true
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue