From 806f71cbe8f8782819f1f989899ac809b97e684c Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Thu, 28 Nov 2024 19:33:53 +0100 Subject: [PATCH] feat(colors): optionally get the cursor color from the hl group at the cursor --- lua/smear_cursor/color.lua | 143 ++++++++++++++++++------------------ lua/smear_cursor/events.lua | 2 +- lua/smear_cursor/init.lua | 2 +- 3 files changed, 75 insertions(+), 72 deletions(-) diff --git a/lua/smear_cursor/color.lua b/lua/smear_cursor/color.lua index ea00e27..34f7907 100644 --- a/lua/smear_cursor/color.lua +++ b/lua/smear_cursor/color.lua @@ -3,30 +3,9 @@ local logging = require("smear_cursor.logging") local round = require("smear_cursor.math").round local M = {} --- TODO: does not work -M.get_hl_group = function(row, col) - -- Retrieve the current buffer - local buffer_id = vim.api.nvim_get_current_buf() - - local extmarks = vim.api.nvim_buf_get_extmarks(buffer_id, -1, { row, col }, { row, col + 1 }, { - details = true, - overlap = true, - }) - logging.debug(vim.inspect(extmarks)) - - if #extmarks > 0 then - local extmark = extmarks[1] - if extmark[4] and extmark[4].hl_group then - return extmark[4].hl_group - end - end - - return "Normal" -end - -- Get a color from a highlight group local function get_hl_color(group, attr) - local hl = vim.api.nvim_get_hl_by_name(group, true) + local hl = vim.api.nvim_get_hl(0, { name = group, link = false }) if hl[attr] then return string.format("#%06x", hl[attr]) end @@ -36,6 +15,7 @@ end local cursor_color = nil local normal_bg = nil local transparent_bg_fallback_color = "#303030" +local cache = {} ---@type table local function hex_to_rgb(hex) hex = hex:gsub("#", "") @@ -58,72 +38,95 @@ local function interpolate_colors(hex1, hex2, t) return rgb_to_hex(r, g, b) end -M.set_hl_groups = function() +function M.clear() + cache = {} +end + +---@param opts? {level?: number, inverted?: boolean} +function M.get_hl_group(opts) + opts = opts or {} + local _cursor_color ---@type string? + + local hl_group = ("SmearCursorNormal%s"):format(opts.inverted and "Inverted" or "", opts.level or 0) + + -- Get the cursor color from the treesitter highlight group + -- at the cursor. + if cursor_color == "treesitter" and vim.b.ts_highlight then + local cursor = vim.api.nvim_win_get_cursor(0) + local ts_hl_group ---@type string? + for _, capture in pairs(vim.treesitter.get_captures_at_pos(0, cursor[1] - 1, cursor[2])) do + ts_hl_group = "@" .. capture.capture .. "." .. capture.lang + end + local ts_color = ts_hl_group and get_hl_color(ts_hl_group, "fg") + if ts_color then + _cursor_color = ts_color + hl_group = hl_group .. "_" .. ts_color:sub(2) + end + end + + if cache[hl_group] then + return hl_group + end + + local _normal_bg = normal_bg or get_hl_color("Normal", "bg") or "none" + -- Retrieve the cursor color and the normal background color if not set by the user - local _cursor_color = cursor_color - or get_hl_color("Cursor", "background") - or get_hl_color("Normal", "foreground") - or "#d0d0d0" - local _normal_bg = normal_bg or get_hl_color("Normal", "background") or "none" + _cursor_color = _cursor_color or get_hl_color("Cursor", "bg") or get_hl_color("Normal", "fg") or "#d0d0d0" -- Blending breaks with transparent backgrounds local blending = config.legacy_computing_symbols_support and _normal_bg ~= "none" - vim.api.nvim_set_hl(0, M.hl_group, { - fg = _cursor_color, - bg = "none", - blend = blending and 100 or 0, - }) - vim.api.nvim_set_hl( - 0, - M.hl_group_inverted, - -- Blending does not work as we'd like with reversed colors - { fg = _normal_bg == "none" and transparent_bg_fallback_color or _normal_bg, bg = _cursor_color, blend = 0 } - ) - - M.hl_groups = {} - M.hl_groups_inverted = {} - - for i = 1, config.color_levels do - local opacity = (i / config.color_levels) ^ (1 / config.gamma) - local blended_cursor_color = interpolate_colors( + if opts.level then + local opacity = (opts.level / config.color_levels) ^ (1 / config.gamma) + _cursor_color = interpolate_colors( _normal_bg == "none" and transparent_bg_fallback_color or _normal_bg, _cursor_color, opacity ) - local blended_hl_group = M.hl_group .. i - local blended_hl_group_inverted = M.hl_group_inverted .. i - M.hl_groups[i] = blended_hl_group - M.hl_groups_inverted[i] = blended_hl_group_inverted - - vim.api.nvim_set_hl(0, blended_hl_group, { - fg = blended_cursor_color, - bg = _normal_bg, - blend = blending and 100 or 0, - }) - vim.api.nvim_set_hl(0, blended_hl_group_inverted, { - fg = _normal_bg == "none" and transparent_bg_fallback_color or _normal_bg, - bg = blended_cursor_color, - blend = 0, - }) end + + ---@type vim.api.keyset.highlight + local hl = opts.inverted + and { + fg = _normal_bg == "none" and transparent_bg_fallback_color or _normal_bg, + bg = _cursor_color, + blend = 0, + } + or { + fg = _cursor_color, + bg = "none", -- _normal_bg, + blend = blending and 100 or 0, + } + + vim.api.nvim_set_hl(0, hl_group, hl) + cache[hl_group] = true + return hl_group end -- Define new highlight groups using the retrieved colors -M.hl_group = "SmearCursorNormal" -M.hl_group_inverted = "SmearCursorNormalInverted" -M.hl_groups = {} -M.hl_groups_inverted = {} -M.set_hl_groups() +M.hl_groups = setmetatable({}, { + __index = function(_, key) + return M.get_hl_group({ level = key }) + end, +}) +M.hl_groups_inverted = setmetatable({}, { + __index = function(_, key) + return M.get_hl_group({ level = key, inverted = true }) + end, +}) local metatable = { - __index = function(table, key) + __index = function(_, key) if key == "cursor_color" then return cursor_color elseif key == "normal_bg" then return normal_bg elseif key == "transparent_bg_fallback_color" then return transparent_bg_fallback_color + elseif key == "hl_group" then + return M.get_hl_group() + elseif key == "hl_group_inverted" then + return M.get_hl_group({ inverted = true }) else return nil end @@ -132,13 +135,13 @@ local metatable = { __newindex = function(table, key, value) if key == "cursor_color" then cursor_color = value - M.set_hl_groups() + M.clear() elseif key == "normal_bg" then normal_bg = value - M.set_hl_groups() + M.clear() elseif key == "transparent_bg_fallback_color" then transparent_bg_fallback_color = value - M.set_hl_groups() + M.clear() else rawset(table, key, value) end diff --git a/lua/smear_cursor/events.lua b/lua/smear_cursor/events.lua index 95f6ea9..a4b97db 100644 --- a/lua/smear_cursor/events.lua +++ b/lua/smear_cursor/events.lua @@ -38,7 +38,7 @@ M.listen = function() autocmd CursorMoved * lua require("smear_cursor.events").move_cursor() autocmd CursorMovedI,WinScrolled * lua require("smear_cursor.events").jump_cursor() autocmd BufLeave * lua require("smear_cursor.events").flag_switching_buffer() - autocmd ColorScheme * lua require("smear_cursor.color").set_hl_groups() + autocmd ColorScheme * lua require("smear_cursor.color").clear() augroup END ]], false diff --git a/lua/smear_cursor/init.lua b/lua/smear_cursor/init.lua index b40264b..5600d81 100644 --- a/lua/smear_cursor/init.lua +++ b/lua/smear_cursor/init.lua @@ -38,7 +38,7 @@ local metatable = { color[key] = value elseif key == "legacy_computing_symbols_support" then config.legacy_computing_symbols_support = value - color.set_hl_groups() + color.clear() elseif config[key] ~= nil then config[key] = value else