mirror of
https://github.com/norcalli/nvim-colorizer.lua.git
synced 2026-09-10 07:06:14 -04:00
Fix/132 multiple virtualtext (#133)
* fix: clear all namespaces when detaching from buffer * chore: removes unused tailwind_names namespace * fix: when tailwind = "both", reapply default highlights while avoiding collisions * chore: creates message logger to use vim.api.nvim_echo for nvim >= .11
This commit is contained in:
parent
fb8296c1a9
commit
86c9a6a309
10
Makefile
10
Makefile
|
|
@ -3,6 +3,8 @@ SCRIPTS_DIR=scripts
|
|||
TRIE_TEST_SCRIPT=$(SCRIPTS_DIR)/trie-test.sh
|
||||
TRIE_BENCHMARK_SCRIPT=$(SCRIPTS_DIR)/trie-benchmark.sh
|
||||
MINIMAL_SCRIPT=$(SCRIPTS_DIR)/minimal-colorizer.sh
|
||||
MINIMAL_COLORIZER=colorizer_minimal
|
||||
MINIMAL_TRIE=colorizer_trie
|
||||
|
||||
help:
|
||||
@echo "Available targets:"
|
||||
|
|
@ -27,9 +29,9 @@ minimal:
|
|||
@bash $(MINIMAL_SCRIPT)
|
||||
|
||||
clean:
|
||||
@echo "Removing test/colorizer_repro"
|
||||
@rm -rf test/colorizer_repro
|
||||
@echo "Removing test/trie/colorizer_trie"
|
||||
@rm -rf test/trie/colorizer_trie
|
||||
@echo "Removing test/"$(MINIMAL_COLORIZER)
|
||||
@rm -rf test/$(MINIMAL_COLORIZER)
|
||||
@echo "Removing test/trie/"$(MINIMAL_TRIE)
|
||||
@rm -rf test/trie/$(MINIMAL_TRIE)
|
||||
|
||||
.PHONY: help trie trie-test trie-benchmark minimal clean
|
||||
|
|
|
|||
|
|
@ -405,6 +405,9 @@ function M.detach_from_buffer(bufnr)
|
|||
if bufnr < 0 then
|
||||
return -1
|
||||
end
|
||||
for _, ns_id in pairs(const.namespace) do
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, ns_id, 0, -1)
|
||||
end
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, const.namespace.default, 0, -1)
|
||||
if colorizer_state.buffer_local[bufnr] then
|
||||
for _, namespace in pairs(colorizer_state.buffer_local[bufnr].__detach.ns_id) do
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ local function create_highlight(rgb_hex, mode)
|
|||
if mode == "foreground" then
|
||||
vim.api.nvim_set_hl(0, highlight_name, { fg = "#" .. rgb_hex })
|
||||
else
|
||||
-- TODO: 2025-01-11 - Should this check for background or virtualtext
|
||||
local rr, gg, bb = rgb_hex:sub(1, 2), rgb_hex:sub(3, 4), rgb_hex:sub(5, 6)
|
||||
local r, g, b = tonumber(rr, 16), tonumber(gg, 16), tonumber(bb, 16)
|
||||
local fg_color = color.is_bright(r, g, b) and "Black" or "White"
|
||||
|
|
@ -77,6 +76,59 @@ local function slice_line(bufnr, line, start_col, end_col)
|
|||
return string.sub(lines[1], start_col + 1, end_col)
|
||||
end
|
||||
|
||||
--- Add low priority highlights. Trims highlight ranges to avoid collisions.
|
||||
---@param bufnr number: Buffer number
|
||||
---@param extmarks table: List of low priority extmarks to reapply
|
||||
---@param priority_ns_id number: Namespace id for priority highlights
|
||||
---@param linenr number: Line number
|
||||
local function add_low_priority_highlights(bufnr, extmarks, priority_ns_id, linenr)
|
||||
local priority_marks = vim.api.nvim_buf_get_extmarks(
|
||||
bufnr,
|
||||
priority_ns_id,
|
||||
{ linenr, 0 },
|
||||
{ linenr + 1, 0 },
|
||||
{ details = true }
|
||||
)
|
||||
for _, default_mark in ipairs(extmarks) do
|
||||
local default_start = default_mark[3] -- Start column
|
||||
local default_end = default_mark[4].end_col
|
||||
local hl_group = default_mark[4].hl_group
|
||||
local non_overlapping_ranges = { { default_start, default_end } }
|
||||
for _, lsp_mark in ipairs(priority_marks) do
|
||||
local lsp_start = lsp_mark[3]
|
||||
local lsp_end = lsp_mark[4].end_col
|
||||
-- Adjust ranges to avoid collisions
|
||||
local new_ranges = {}
|
||||
for _, range in ipairs(non_overlapping_ranges) do
|
||||
local start, end_ = range[1], range[2]
|
||||
if lsp_start <= end_ and lsp_end >= start then
|
||||
-- Collision detected, split range
|
||||
if start < lsp_start then
|
||||
table.insert(new_ranges, { start, lsp_start })
|
||||
end
|
||||
if lsp_end < end_ then
|
||||
table.insert(new_ranges, { lsp_end, end_ })
|
||||
end
|
||||
else
|
||||
-- No collision, keep range
|
||||
table.insert(new_ranges, { start, end_ })
|
||||
end
|
||||
end
|
||||
non_overlapping_ranges = new_ranges
|
||||
end
|
||||
for _, range in ipairs(non_overlapping_ranges) do
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
bufnr,
|
||||
default_mark[4].ns_id, -- Original namespace
|
||||
hl_group,
|
||||
linenr,
|
||||
range[1],
|
||||
range[2]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Create highlight and set highlights
|
||||
---@param bufnr number: Buffer number (0 for current)
|
||||
---@param ns_id number: Namespace id for which to create highlights
|
||||
|
|
@ -93,37 +145,41 @@ function M.add_highlight(bufnr, ns_id, line_start, line_end, data, ud_opts, hl_o
|
|||
hl_opts = hl_opts or {}
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, ns_id, line_start, line_end)
|
||||
if ud_opts.mode == "background" or ud_opts.mode == "foreground" then
|
||||
local tw_both = ud_opts.tailwind == "both" and hl_opts.tailwind_lsp
|
||||
for linenr, hls in pairs(data) do
|
||||
local marks
|
||||
if tw_both then
|
||||
marks = vim.api.nvim_buf_get_extmarks(
|
||||
bufnr,
|
||||
const.namespace.default,
|
||||
{ linenr, 0 },
|
||||
{ linenr + 1, 0 },
|
||||
{ details = true }
|
||||
)
|
||||
-- clear default namespace to apply LSP highlights, then rehighlight non-overlapping default highlights
|
||||
-- Fixes: https://github.com/catgoose/nvim-colorizer.lua/issues/61
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, const.namespace.default, linenr, linenr + 1)
|
||||
end
|
||||
for _, hl in ipairs(hls) do
|
||||
if ud_opts.tailwind == "both" and hl_opts.tailwind_lsp then
|
||||
vim.api.nvim_buf_clear_namespace(
|
||||
bufnr,
|
||||
const.namespace.tailwind_names,
|
||||
linenr,
|
||||
linenr + 1
|
||||
)
|
||||
if ud_opts.tailwind_opts.update_names then
|
||||
local txt = slice_line(bufnr, linenr, hl.range[1], hl.range[2])
|
||||
if txt and not hl_state.updated_colors[txt] then
|
||||
hl_state.updated_colors[txt] = true
|
||||
names.update_color(txt, hl.rgb_hex)
|
||||
end
|
||||
if tw_both and ud_opts.tailwind_opts.update_names then
|
||||
local txt = slice_line(bufnr, linenr, hl.range[1], hl.range[2])
|
||||
if txt and not hl_state.updated_colors[txt] then
|
||||
hl_state.updated_colors[txt] = true
|
||||
names.update_color(txt, hl.rgb_hex)
|
||||
end
|
||||
end
|
||||
local hlname = create_highlight(hl.rgb_hex, ud_opts.mode)
|
||||
vim.api.nvim_buf_add_highlight(bufnr, ns_id, hlname, linenr, hl.range[1], hl.range[2])
|
||||
end
|
||||
if tw_both then
|
||||
add_low_priority_highlights(bufnr, marks, ns_id, linenr)
|
||||
end
|
||||
end
|
||||
elseif ud_opts.mode == "virtualtext" then
|
||||
for linenr, hls in pairs(data) do
|
||||
for _, hl in ipairs(hls) do
|
||||
if ud_opts.tailwind == "both" and hl_opts.tailwind_lsp then
|
||||
vim.api.nvim_buf_clear_namespace(
|
||||
bufnr,
|
||||
const.namespace.tailwind_names,
|
||||
linenr,
|
||||
linenr + 1
|
||||
)
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, ns_id, linenr, linenr + 1)
|
||||
if ud_opts.tailwind_opts.update_names then
|
||||
local txt = slice_line(bufnr, linenr, hl.range[1], hl.range[2])
|
||||
if txt and not hl_state.updated_colors[txt] then
|
||||
|
|
@ -204,11 +260,6 @@ function M.highlight(bufnr, ns_id, line_start, line_end, ud_opts, buf_local_opts
|
|||
-- Parse lines from matcher
|
||||
local data = M.parse_lines(bufnr, lines, line_start, ud_opts) or {}
|
||||
M.add_highlight(bufnr, ns_id, line_start, line_end, data, ud_opts)
|
||||
-- Tailwind parsing
|
||||
if ud_opts.tailwind == "normal" or ud_opts.tailwind == "both" then
|
||||
local tw_data = M.parse_lines(bufnr, lines, line_start, ud_opts, { tailwind = true }) or {}
|
||||
M.add_highlight(bufnr, const.namespace.tailwind_names, line_start, line_end, tw_data, ud_opts)
|
||||
end
|
||||
if ud_opts.tailwind == "lsp" or ud_opts.tailwind == "both" then
|
||||
tailwind.lsp_highlight(
|
||||
bufnr,
|
||||
|
|
@ -230,11 +281,8 @@ end
|
|||
---@param lines table: Table of lines to parse
|
||||
---@param line_start number: Buffer line number to start highlighting
|
||||
---@param ud_opts table: `user_default_options`
|
||||
---@param parse_opts table|nil: Parsing options
|
||||
--- - tailwind boolean|nil: use tailwind_names parser
|
||||
---@return table|nil
|
||||
function M.parse_lines(bufnr, lines, line_start, ud_opts, parse_opts)
|
||||
parse_opts = parse_opts or {}
|
||||
function M.parse_lines(bufnr, lines, line_start, ud_opts)
|
||||
local loop_parse_fn = matcher.make(ud_opts)
|
||||
if not loop_parse_fn then
|
||||
return
|
||||
|
|
@ -247,7 +295,7 @@ function M.parse_lines(bufnr, lines, line_start, ud_opts, parse_opts)
|
|||
while i < #line do
|
||||
local length, rgb_hex = loop_parse_fn(line, i, bufnr)
|
||||
if length and not rgb_hex then
|
||||
vim.api.nvim_err_writeln(
|
||||
utils.log_message(
|
||||
string.format(
|
||||
"Colorizer: Error parsing line %d, index %d. Please report this issue.",
|
||||
line_nr,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ M.plugin = {
|
|||
-- - tailwind - Namespace used for creating extmarks to prevent tailwind name parsing from overwriting tailwind lsp highlights
|
||||
M.namespace = {
|
||||
default = vim.api.nvim_create_namespace(M.plugin.name),
|
||||
tailwind_names = vim.api.nvim_create_namespace(M.plugin.name .. "_tailwind_names"),
|
||||
tailwind_lsp = vim.api.nvim_create_namespace(M.plugin.name .. "_tailwind_lsp"),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ parsers.prefix = {
|
|||
["_hsla"] = parsers.hsl_function,
|
||||
}
|
||||
|
||||
-- TODO: 2024-12-31 - Return multiple parse_fn for tailwind parser?
|
||||
|
||||
---Form a trie stuct with the given prefixes
|
||||
---@param matchers table: List of prefixes, {"rgb", "hsl"}
|
||||
---@param matchers_trie table: Table containing information regarding non-trie based parsers
|
||||
|
|
|
|||
|
|
@ -77,9 +77,7 @@ local function handle_names_custom(names_custom)
|
|||
if status and type(result) == "table" then
|
||||
names = result
|
||||
else
|
||||
vim.api.nvim_err_writeln(
|
||||
"Error in names_custom function: " .. (result or "Invalid return value")
|
||||
)
|
||||
utils.log_message("Error in names_custom function: " .. (result or "Invalid return value"))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
|
@ -92,11 +90,11 @@ local function handle_names_custom(names_custom)
|
|||
if normalized_hex:match("^%x%x%x%x%x%x$") then
|
||||
add_color(name, normalized_hex)
|
||||
else
|
||||
vim.api.nvim_err_writeln("Invalid hex code for '" .. name .. "': " .. normalized_hex)
|
||||
utils.log_message(string.format("Invalid hex code for '%s': %s", name, normalized_hex))
|
||||
end
|
||||
else
|
||||
vim.api.nvim_err_writeln(
|
||||
"Invalid value for '" .. name .. "': Expected string, got " .. type(hex)
|
||||
utils.log_message(
|
||||
string.format("Invalid value for '%s': Expected string, got %s", name, type(hex))
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ local function highlight(bufnr, ud_opts, add_highlight)
|
|||
lsp_cache[bufnr].document_params,
|
||||
function(err, results, _, _)
|
||||
if err ~= nil then
|
||||
vim.api.nvim_err_writeln("tailwind.highlight: Error: " .. err)
|
||||
utils.log_message("tailwind.highlight: Error: " .. err)
|
||||
end
|
||||
if err == nil and results ~= nil then
|
||||
local data, line_start, line_end = {}, nil, nil
|
||||
|
|
|
|||
|
|
@ -224,4 +224,12 @@ function M.visible_line_range(bufnr)
|
|||
return range[1] - 1, range[2]
|
||||
end
|
||||
|
||||
function M.log_message(message)
|
||||
if vim.version().minor >= 11 then
|
||||
vim.api.nvim_echo({ { message, "ErrorMsg" } }, true, {})
|
||||
else
|
||||
vim.api.nvim_err_writeln(message)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
|
|||
2
test/.gitignore
vendored
2
test/.gitignore
vendored
|
|
@ -1,2 +1,2 @@
|
|||
colorizer_repro/
|
||||
colorizer_minimal/
|
||||
colorizer_trie/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
-- Run this file as `nvim --clean -u minimal-colorizer.lua`
|
||||
|
||||
local settings = {
|
||||
use_remote = false, -- Use colorizer master or local git directory
|
||||
base_dir = "colorizer_repro", -- Directory to clone lazy.nvim
|
||||
use_remote = true, -- Use colorizer master or local git directory
|
||||
base_dir = "colorizer_minimal", -- Directory to clone lazy.nvim
|
||||
local_plugin_dir = os.getenv("HOME") .. "/git/nvim-colorizer.lua", -- Local git directory for colorizer. Used if use_remote is false
|
||||
expect = "expect.lua",
|
||||
plugins = { -- add any additional plugins
|
||||
|
|
|
|||
Loading…
Reference in a new issue