diff --git a/doc/fugitive-ts.nvim.txt b/doc/fugitive-ts.nvim.txt index 9d5e5de..4945f0c 100644 --- a/doc/fugitive-ts.nvim.txt +++ b/doc/fugitive-ts.nvim.txt @@ -56,11 +56,6 @@ CONFIGURATION *fugitive-ts-config* Example: >lua disabled_languages = { 'markdown', 'text' } < - {highlight_headers} (boolean, default: true) - Highlight function context in hunk headers. - The context portion of `@@ -10,3 +10,4 @@ func()` - will receive treesitter highlighting. - {debounce_ms} (integer, default: 50) Debounce delay in milliseconds for re-highlighting after buffer changes. Lower values feel snappier @@ -70,6 +65,38 @@ CONFIGURATION *fugitive-ts-config* Skip treesitter highlighting for hunks larger than this many lines. Prevents lag on massive diffs. + {conceal_prefixes} (boolean, default: true) + Hide diff prefixes (`+`/`-`/` `) using virtual + text overlay. Makes code appear without the + leading diff character. When `highlights.background` + is also enabled, the overlay inherits the line's + background color. + + {highlights} (table, default: see below) + Controls which highlight features are enabled. + See |fugitive-ts.Highlights| for fields. + + *fugitive-ts.Highlights* + Highlights table fields: ~ + {treesitter} (boolean, default: true) + Apply treesitter syntax highlighting to code. + + {background} (boolean, default: true) + Apply background highlighting to `+`/`-` lines + using `FugitiveTsAdd`/`FugitiveTsDelete` groups + (derived from `DiffAdd`/`DiffDelete` backgrounds). + + {linenr} (boolean, default: true) + Highlight line numbers with matching colors. + Only visible if line numbers are enabled. + + {vim} (boolean, default: false) + Experimental: Use vim syntax highlighting as + fallback when no treesitter parser is available. + + Note: Header context (e.g., `@@ -10,3 +10,4 @@ func()`) is always + highlighted with treesitter when a parser is available. + ============================================================================== API *fugitive-ts-api* @@ -103,8 +130,10 @@ IMPLEMENTATION *fugitive-ts-implementation* - Language is detected from the filename using |vim.filetype.match()| - Diff prefixes (`+`/`-`/` `) are stripped from code lines - Code is parsed with |vim.treesitter.get_string_parser()| + - Background extmarks (`FugitiveTsAdd`/`FugitiveTsDelete`) at priority 198 + - `Normal` extmarks at priority 199 clear underlying diff foreground - Treesitter highlights are applied as extmarks at priority 200 - - A `Normal` extmark at priority 199 clears underlying diff colors + - Virtual text overlays hide diff prefixes when `conceal_prefixes` is enabled 4. Re-highlighting occurs on `TextChanged` (debounced) and `Syntax` events ============================================================================== diff --git a/lua/fugitive-ts/highlight.lua b/lua/fugitive-ts/highlight.lua index 6286f10..8c95ceb 100644 --- a/lua/fugitive-ts/highlight.lua +++ b/lua/fugitive-ts/highlight.lua @@ -1,8 +1,18 @@ local M = {} +local debug_enabled = false + +---@param enabled boolean +function M.set_debug(enabled) + debug_enabled = enabled +end + ---@param msg string ---@param ... any local function dbg(msg, ...) + if not debug_enabled then + return + end local formatted = string.format(msg, ...) vim.notify('[fugitive-ts] ' .. formatted, vim.log.levels.DEBUG) end @@ -13,9 +23,8 @@ end ---@param col_offset integer ---@param text string ---@param lang string ----@param debug? boolean ---@return integer -local function highlight_text(bufnr, ns, hunk, col_offset, text, lang, debug) +local function highlight_text(bufnr, ns, hunk, col_offset, text, lang) local ok, parser_obj = pcall(vim.treesitter.get_string_parser, text, lang) if not ok or not parser_obj then return 0 @@ -55,28 +64,29 @@ local function highlight_text(bufnr, ns, hunk, col_offset, text, lang, debug) return extmark_count end +---@class fugitive-ts.HunkOpts +---@field max_lines integer +---@field conceal_prefixes boolean +---@field highlights fugitive-ts.Highlights + ---@param bufnr integer ---@param ns integer ---@param hunk fugitive-ts.Hunk ----@param max_lines integer ----@param highlight_headers boolean ----@param debug? boolean -function M.highlight_hunk(bufnr, ns, hunk, max_lines, highlight_headers, debug) +---@param opts fugitive-ts.HunkOpts +function M.highlight_hunk(bufnr, ns, hunk, opts) local lang = hunk.lang if not lang then return end - if #hunk.lines > max_lines then - if debug then - dbg( - 'skipping hunk %s:%d (%d lines > %d max)', - hunk.filename, - hunk.start_line, - #hunk.lines, - max_lines - ) - end + if #hunk.lines > opts.max_lines then + dbg( + 'skipping hunk %s:%d (%d lines > %d max)', + hunk.filename, + hunk.start_line, + #hunk.lines, + opts.max_lines + ) return end @@ -93,29 +103,23 @@ function M.highlight_hunk(bufnr, ns, hunk, max_lines, highlight_headers, debug) local ok, parser_obj = pcall(vim.treesitter.get_string_parser, code, lang) if not ok or not parser_obj then - if debug then - dbg('failed to create parser for lang: %s', lang) - end + dbg('failed to create parser for lang: %s', lang) return end local trees = parser_obj:parse() if not trees or #trees == 0 then - if debug then - dbg('parse returned no trees for lang: %s', lang) - end + dbg('parse returned no trees for lang: %s', lang) return end local query = vim.treesitter.query.get(lang, 'highlights') if not query then - if debug then - dbg('no highlights query for lang: %s', lang) - end + dbg('no highlights query for lang: %s', lang) return end - if highlight_headers and hunk.header_context and hunk.header_context_col then + if hunk.header_context and hunk.header_context_col then local header_line = hunk.start_line - 1 pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, header_line, hunk.header_context_col, { end_col = hunk.header_context_col + #hunk.header_context, @@ -123,8 +127,8 @@ function M.highlight_hunk(bufnr, ns, hunk, max_lines, highlight_headers, debug) priority = 199, }) local header_extmarks = - highlight_text(bufnr, ns, hunk, hunk.header_context_col, hunk.header_context, lang, debug) - if debug and header_extmarks > 0 then + highlight_text(bufnr, ns, hunk, hunk.header_context_col, hunk.header_context, lang) + if header_extmarks > 0 then dbg('header %s:%d applied %d extmarks', hunk.filename, hunk.start_line, header_extmarks) end end @@ -132,7 +136,32 @@ function M.highlight_hunk(bufnr, ns, hunk, max_lines, highlight_headers, debug) for i, line in ipairs(hunk.lines) do local buf_line = hunk.start_line + i - 1 local line_len = #line - if line_len > 1 then + 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.linenr 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', @@ -141,6 +170,10 @@ function M.highlight_hunk(bufnr, ns, hunk, max_lines, highlight_headers, debug) end end + if not opts.highlights.treesitter then + return + end + local extmark_count = 0 for id, node, _ in query:iter_captures(trees[1]:root(), code) do local capture_name = '@' .. query.captures[id] @@ -160,9 +193,7 @@ function M.highlight_hunk(bufnr, ns, hunk, max_lines, highlight_headers, debug) extmark_count = extmark_count + 1 end - if debug then - dbg('hunk %s:%d applied %d extmarks', hunk.filename, hunk.start_line, extmark_count) - end + dbg('hunk %s:%d applied %d extmarks', hunk.filename, hunk.start_line, extmark_count) end return M diff --git a/lua/fugitive-ts/init.lua b/lua/fugitive-ts/init.lua index 31084a2..bc965d4 100644 --- a/lua/fugitive-ts/init.lua +++ b/lua/fugitive-ts/init.lua @@ -1,11 +1,18 @@ +---@class fugitive-ts.Highlights +---@field treesitter boolean +---@field background boolean +---@field linenr boolean +---@field vim boolean + ---@class fugitive-ts.Config ---@field enabled boolean ---@field debug boolean ---@field languages table ---@field disabled_languages string[] ----@field highlight_headers boolean ---@field debounce_ms integer ---@field max_lines_per_hunk integer +---@field conceal_prefixes boolean +---@field highlights fugitive-ts.Highlights ---@class fugitive-ts ---@field attach fun(bufnr?: integer) @@ -24,9 +31,15 @@ local default_config = { debug = false, languages = {}, disabled_languages = {}, - highlight_headers = true, debounce_ms = 50, max_lines_per_hunk = 500, + conceal_prefixes = true, + highlights = { + treesitter = true, + background = true, + linenr = true, + vim = false, + }, } ---@type fugitive-ts.Config @@ -57,18 +70,14 @@ local function highlight_buffer(bufnr) vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1) - local hunks = - parser.parse_buffer(bufnr, config.languages, config.disabled_languages, config.debug) + local hunks = parser.parse_buffer(bufnr, config.languages, config.disabled_languages) dbg('found %d hunks in buffer %d', #hunks, bufnr) for _, hunk in ipairs(hunks) do - highlight.highlight_hunk( - bufnr, - ns, - hunk, - config.max_lines_per_hunk, - config.highlight_headers, - config.debug - ) + highlight.highlight_hunk(bufnr, ns, hunk, { + max_lines = config.max_lines_per_hunk, + conceal_prefixes = config.conceal_prefixes, + highlights = config.highlights, + }) end end @@ -92,9 +101,9 @@ local function create_debounced_highlight(bufnr) config.debounce_ms, 0, vim.schedule_wrap(function() - t:close() if timer == t then timer = nil + t:close() end highlight_buffer(bufnr) end) @@ -147,7 +156,35 @@ end ---@param opts? fugitive-ts.Config function M.setup(opts) opts = opts or {} + + vim.validate({ + enabled = { opts.enabled, 'boolean', true }, + debug = { opts.debug, 'boolean', true }, + languages = { opts.languages, 'table', true }, + disabled_languages = { opts.disabled_languages, 'table', true }, + debounce_ms = { opts.debounce_ms, 'number', true }, + max_lines_per_hunk = { opts.max_lines_per_hunk, 'number', true }, + conceal_prefixes = { opts.conceal_prefixes, 'boolean', true }, + highlights = { opts.highlights, 'table', true }, + }) + + if opts.highlights then + vim.validate({ + ['highlights.treesitter'] = { opts.highlights.treesitter, 'boolean', true }, + ['highlights.background'] = { opts.highlights.background, 'boolean', true }, + ['highlights.linenr'] = { opts.highlights.linenr, 'boolean', true }, + ['highlights.vim'] = { opts.highlights.vim, 'boolean', true }, + }) + end + config = vim.tbl_deep_extend('force', default_config, opts) + parser.set_debug(config.debug) + highlight.set_debug(config.debug) + + local diff_add = vim.api.nvim_get_hl(0, { name = 'DiffAdd' }) + local diff_delete = vim.api.nvim_get_hl(0, { name = 'DiffDelete' }) + vim.api.nvim_set_hl(0, 'FugitiveTsAdd', { bg = diff_add.bg }) + vim.api.nvim_set_hl(0, 'FugitiveTsDelete', { bg = diff_delete.bg }) end return M diff --git a/lua/fugitive-ts/parser.lua b/lua/fugitive-ts/parser.lua index 8cd119b..fa0bd16 100644 --- a/lua/fugitive-ts/parser.lua +++ b/lua/fugitive-ts/parser.lua @@ -8,9 +8,19 @@ local M = {} +local debug_enabled = false + +---@param enabled boolean +function M.set_debug(enabled) + debug_enabled = enabled +end + ---@param msg string ---@param ... any local function dbg(msg, ...) + if not debug_enabled then + return + end local formatted = string.format(msg, ...) vim.notify('[fugitive-ts] ' .. formatted, vim.log.levels.DEBUG) end @@ -18,15 +28,12 @@ end ---@param filename string ---@param custom_langs? table ---@param disabled_langs? string[] ----@param debug? boolean ---@return string? -local function get_lang_from_filename(filename, custom_langs, disabled_langs, debug) +local function get_lang_from_filename(filename, custom_langs, disabled_langs) if custom_langs and custom_langs[filename] then local lang = custom_langs[filename] if disabled_langs and vim.tbl_contains(disabled_langs, lang) then - if debug then - dbg('lang disabled: %s', lang) - end + dbg('lang disabled: %s', lang) return nil end return lang @@ -34,28 +41,22 @@ local function get_lang_from_filename(filename, custom_langs, disabled_langs, de local ft = vim.filetype.match({ filename = filename }) if not ft then - if debug then - dbg('no filetype for: %s', filename) - end + dbg('no filetype for: %s', filename) return nil end local lang = vim.treesitter.language.get_lang(ft) if lang then if disabled_langs and vim.tbl_contains(disabled_langs, lang) then - if debug then - dbg('lang disabled: %s', lang) - end + dbg('lang disabled: %s', lang) return nil end local ok = pcall(vim.treesitter.language.inspect, lang) if ok then return lang end - if debug then - dbg('no parser for lang: %s (ft: %s)', lang, ft) - end - elseif debug then + dbg('no parser for lang: %s (ft: %s)', lang, ft) + else dbg('no ts lang for filetype: %s', ft) end @@ -65,9 +66,8 @@ end ---@param bufnr integer ---@param custom_langs? table ---@param disabled_langs? string[] ----@param debug? boolean ---@return fugitive-ts.Hunk[] -function M.parse_buffer(bufnr, custom_langs, disabled_langs, debug) +function M.parse_buffer(bufnr, custom_langs, disabled_langs) local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) ---@type fugitive-ts.Hunk[] local hunks = {} @@ -107,8 +107,8 @@ function M.parse_buffer(bufnr, custom_langs, disabled_langs, debug) if filename then flush_hunk() current_filename = filename - current_lang = get_lang_from_filename(filename, custom_langs, disabled_langs, debug) - if debug and current_lang then + current_lang = get_lang_from_filename(filename, custom_langs, disabled_langs) + if current_lang then dbg('file: %s -> lang: %s', filename, current_lang) end elseif line:match('^@@.-@@') then diff --git a/spec/highlight_spec.lua b/spec/highlight_spec.lua index 62d57b8..fcdf8dd 100644 --- a/spec/highlight_spec.lua +++ b/spec/highlight_spec.lua @@ -7,6 +7,10 @@ describe('highlight', function() before_each(function() ns = vim.api.nvim_create_namespace('fugitive_ts_test') + local diff_add = vim.api.nvim_get_hl(0, { name = 'DiffAdd' }) + local diff_delete = vim.api.nvim_get_hl(0, { name = 'DiffDelete' }) + vim.api.nvim_set_hl(0, 'FugitiveTsAdd', { bg = diff_add.bg }) + vim.api.nvim_set_hl(0, 'FugitiveTsDelete', { bg = diff_delete.bg }) end) local function create_buffer(lines) @@ -25,6 +29,31 @@ describe('highlight', function() return vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, { details = true }) end + local function default_opts(overrides) + local opts = { + max_lines = 500, + conceal_prefixes = false, + highlights = { + treesitter = true, + background = false, + linenr = false, + vim = false, + }, + } + if overrides then + for k, v in pairs(overrides) do + if k == 'highlights' then + for hk, hv in pairs(v) do + opts.highlights[hk] = hv + end + else + opts[k] = v + end + end + end + return opts + end + it('applies extmarks for lua code', function() local bufnr = create_buffer({ '@@ -1,1 +1,2 @@', @@ -39,7 +68,7 @@ describe('highlight', function() lines = { ' local x = 1', '+local y = 2' }, } - highlight.highlight_hunk(bufnr, ns, hunk, 500, false, false) + highlight.highlight_hunk(bufnr, ns, hunk, default_opts()) local extmarks = get_extmarks(bufnr) assert.is_true(#extmarks > 0) @@ -60,7 +89,7 @@ describe('highlight', function() lines = { ' local x = 1', '+local y = 2' }, } - highlight.highlight_hunk(bufnr, ns, hunk, 500, false, false) + highlight.highlight_hunk(bufnr, ns, hunk, default_opts()) local extmarks = get_extmarks(bufnr) local has_normal = false @@ -90,7 +119,7 @@ describe('highlight', function() lines = hunk_lines, } - highlight.highlight_hunk(bufnr, ns, hunk, 500, false, false) + highlight.highlight_hunk(bufnr, ns, hunk, default_opts()) local extmarks = get_extmarks(bufnr) assert.are.equal(0, #extmarks) @@ -111,7 +140,7 @@ describe('highlight', function() lines = { ' some content', '+more content' }, } - highlight.highlight_hunk(bufnr, ns, hunk, 500, false, false) + highlight.highlight_hunk(bufnr, ns, hunk, default_opts()) local extmarks = get_extmarks(bufnr) assert.are.equal(0, #extmarks) @@ -134,7 +163,7 @@ describe('highlight', function() lines = { ' local x = 1', '+local y = 2' }, } - highlight.highlight_hunk(bufnr, ns, hunk, 500, true, false) + highlight.highlight_hunk(bufnr, ns, hunk, default_opts()) local extmarks = get_extmarks(bufnr) local has_header_extmark = false @@ -148,9 +177,9 @@ describe('highlight', function() delete_buffer(bufnr) end) - it('does not highlight header when disabled', function() + it('does not highlight header when no header_context', function() local bufnr = create_buffer({ - '@@ -10,3 +10,4 @@ function hello()', + '@@ -10,3 +10,4 @@', ' local x = 1', }) @@ -158,12 +187,10 @@ describe('highlight', function() filename = 'test.lua', lang = 'lua', start_line = 1, - header_context = 'function hello()', - header_context_col = 18, lines = { ' local x = 1' }, } - highlight.highlight_hunk(bufnr, ns, hunk, 500, false, false) + highlight.highlight_hunk(bufnr, ns, hunk, default_opts()) local extmarks = get_extmarks(bufnr) local header_extmarks = 0 @@ -189,7 +216,7 @@ describe('highlight', function() } assert.has_no.errors(function() - highlight.highlight_hunk(bufnr, ns, hunk, 500, false, false) + highlight.highlight_hunk(bufnr, ns, hunk, default_opts()) end) delete_buffer(bufnr) end) @@ -209,9 +236,294 @@ describe('highlight', function() } assert.has_no.errors(function() - highlight.highlight_hunk(bufnr, ns, hunk, 500, false, false) + highlight.highlight_hunk(bufnr, ns, hunk, default_opts()) end) delete_buffer(bufnr) end) + + it('applies overlay extmarks when conceal_prefixes enabled', function() + local bufnr = create_buffer({ + '@@ -1,1 +1,2 @@', + ' local x = 1', + '+local y = 2', + }) + + local hunk = { + filename = 'test.lua', + lang = 'lua', + start_line = 1, + lines = { ' local x = 1', '+local y = 2' }, + } + + highlight.highlight_hunk(bufnr, ns, hunk, default_opts({ conceal_prefixes = true })) + + local extmarks = get_extmarks(bufnr) + local overlay_count = 0 + for _, mark in ipairs(extmarks) do + if mark[4] and mark[4].virt_text_pos == 'overlay' then + overlay_count = overlay_count + 1 + end + end + assert.are.equal(2, overlay_count) + delete_buffer(bufnr) + end) + + it('does not apply overlay extmarks when conceal_prefixes disabled', function() + local bufnr = create_buffer({ + '@@ -1,1 +1,2 @@', + ' local x = 1', + '+local y = 2', + }) + + local hunk = { + filename = 'test.lua', + lang = 'lua', + start_line = 1, + lines = { ' local x = 1', '+local y = 2' }, + } + + highlight.highlight_hunk(bufnr, ns, hunk, default_opts({ conceal_prefixes = false })) + + local extmarks = get_extmarks(bufnr) + local overlay_count = 0 + for _, mark in ipairs(extmarks) do + if mark[4] and mark[4].virt_text_pos == 'overlay' then + overlay_count = overlay_count + 1 + end + end + assert.are.equal(0, overlay_count) + delete_buffer(bufnr) + end) + + it('applies DiffAdd background to + lines when background enabled', function() + local bufnr = create_buffer({ + '@@ -1,1 +1,2 @@', + ' local x = 1', + '+local y = 2', + }) + + local hunk = { + filename = 'test.lua', + lang = 'lua', + start_line = 1, + lines = { ' local x = 1', '+local y = 2' }, + } + + highlight.highlight_hunk( + bufnr, + ns, + hunk, + default_opts({ highlights = { background = true } }) + ) + + local extmarks = get_extmarks(bufnr) + local has_diff_add = false + for _, mark in ipairs(extmarks) do + if mark[4] and mark[4].line_hl_group == 'FugitiveTsAdd' then + has_diff_add = true + break + end + end + assert.is_true(has_diff_add) + delete_buffer(bufnr) + end) + + it('applies DiffDelete background to - lines when background enabled', function() + local bufnr = create_buffer({ + '@@ -1,2 +1,1 @@', + ' local x = 1', + '-local y = 2', + }) + + local hunk = { + filename = 'test.lua', + lang = 'lua', + start_line = 1, + lines = { ' local x = 1', '-local y = 2' }, + } + + highlight.highlight_hunk( + bufnr, + ns, + hunk, + default_opts({ highlights = { background = true } }) + ) + + local extmarks = get_extmarks(bufnr) + local has_diff_delete = false + for _, mark in ipairs(extmarks) do + if mark[4] and mark[4].line_hl_group == 'FugitiveTsDelete' then + has_diff_delete = true + break + end + end + assert.is_true(has_diff_delete) + delete_buffer(bufnr) + end) + + it('does not apply background when background disabled', function() + local bufnr = create_buffer({ + '@@ -1,1 +1,2 @@', + ' local x = 1', + '+local y = 2', + }) + + local hunk = { + filename = 'test.lua', + lang = 'lua', + start_line = 1, + lines = { ' local x = 1', '+local y = 2' }, + } + + highlight.highlight_hunk( + bufnr, + ns, + hunk, + default_opts({ highlights = { background = false } }) + ) + + local extmarks = get_extmarks(bufnr) + local has_line_hl = false + for _, mark in ipairs(extmarks) do + if mark[4] and mark[4].line_hl_group then + has_line_hl = true + break + end + end + assert.is_false(has_line_hl) + delete_buffer(bufnr) + end) + + it('applies number_hl_group when linenr enabled', function() + local bufnr = create_buffer({ + '@@ -1,1 +1,2 @@', + ' local x = 1', + '+local y = 2', + }) + + local hunk = { + filename = 'test.lua', + lang = 'lua', + start_line = 1, + lines = { ' local x = 1', '+local y = 2' }, + } + + highlight.highlight_hunk( + bufnr, + ns, + hunk, + default_opts({ highlights = { background = true, linenr = true } }) + ) + + local extmarks = get_extmarks(bufnr) + local has_number_hl = false + for _, mark in ipairs(extmarks) do + if mark[4] and mark[4].number_hl_group then + has_number_hl = true + break + end + end + assert.is_true(has_number_hl) + delete_buffer(bufnr) + end) + + it('does not apply number_hl_group when linenr disabled', function() + local bufnr = create_buffer({ + '@@ -1,1 +1,2 @@', + ' local x = 1', + '+local y = 2', + }) + + local hunk = { + filename = 'test.lua', + lang = 'lua', + start_line = 1, + lines = { ' local x = 1', '+local y = 2' }, + } + + highlight.highlight_hunk( + bufnr, + ns, + hunk, + default_opts({ highlights = { background = true, linenr = false } }) + ) + + local extmarks = get_extmarks(bufnr) + local has_number_hl = false + for _, mark in ipairs(extmarks) do + if mark[4] and mark[4].number_hl_group then + has_number_hl = true + break + end + end + assert.is_false(has_number_hl) + delete_buffer(bufnr) + end) + + it('skips treesitter highlights when treesitter disabled', function() + local bufnr = create_buffer({ + '@@ -1,1 +1,2 @@', + ' local x = 1', + '+local y = 2', + }) + + local hunk = { + filename = 'test.lua', + lang = 'lua', + start_line = 1, + lines = { ' local x = 1', '+local y = 2' }, + } + + highlight.highlight_hunk( + bufnr, + ns, + hunk, + default_opts({ highlights = { treesitter = false, background = true } }) + ) + + local extmarks = get_extmarks(bufnr) + local has_ts_highlight = false + for _, mark in ipairs(extmarks) do + if mark[4] and mark[4].hl_group and mark[4].hl_group:match('^@') then + has_ts_highlight = true + break + end + end + assert.is_false(has_ts_highlight) + delete_buffer(bufnr) + end) + + it('still applies background when treesitter disabled', function() + local bufnr = create_buffer({ + '@@ -1,1 +1,2 @@', + ' local x = 1', + '+local y = 2', + }) + + local hunk = { + filename = 'test.lua', + lang = 'lua', + start_line = 1, + lines = { ' local x = 1', '+local y = 2' }, + } + + highlight.highlight_hunk( + bufnr, + ns, + hunk, + default_opts({ highlights = { treesitter = false, background = true } }) + ) + + local extmarks = get_extmarks(bufnr) + local has_diff_add = false + for _, mark in ipairs(extmarks) do + if mark[4] and mark[4].line_hl_group == 'FugitiveTsAdd' then + has_diff_add = true + break + end + end + assert.is_true(has_diff_add) + delete_buffer(bufnr) + end) end) end) diff --git a/spec/init_spec.lua b/spec/init_spec.lua index 5e7a0ff..5f3b8e8 100644 --- a/spec/init_spec.lua +++ b/spec/init_spec.lua @@ -22,9 +22,15 @@ describe('fugitive-ts', function() debug = true, languages = { ['.envrc'] = 'bash' }, disabled_languages = { 'markdown' }, - highlight_headers = false, debounce_ms = 100, max_lines_per_hunk = 1000, + conceal_prefixes = false, + highlights = { + treesitter = true, + background = true, + linenr = true, + vim = false, + }, }) end) end)