Skip to content

Commit

Permalink
feat(colors): optionally get the cursor color from the hl group at th…
Browse files Browse the repository at this point in the history
…e cursor
  • Loading branch information
folke committed Nov 28, 2024
1 parent 4c3a56f commit 806f71c
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 72 deletions.
143 changes: 73 additions & 70 deletions lua/smear_cursor/color.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -36,6 +15,7 @@ end
local cursor_color = nil
local normal_bg = nil
local transparent_bg_fallback_color = "#303030"
local cache = {} ---@type table<string, boolean>

local function hex_to_rgb(hex)
hex = hex:gsub("#", "")
Expand All @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lua/smear_cursor/events.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lua/smear_cursor/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 806f71c

Please sign in to comment.