J. Bromley f1dbb2f4a8 Fixed using 'auto' theme with default colorscheme.
When setting theme to 'auto' and using the default colorscheme, lualine
would report "theme not found, defaulting to gruvbox". Fixed by checking
that we get an actual color back when calling utils.extract_highlight_colors
before attempting to apply a brightness modifier.

* Fix brightness_modifier application.

The brightness_modifer() should only be applied when a normal color was
found.

* Apply brightness modifier when normal color not nil.

Moved application of brightness_modifier outside the if statement that
negates the brightness modifier. The modifier will now be applied when
get_color_brightness returns < 0.5.
2021-07-29 22:47:07 +06:00

168 lines
5.6 KiB
Lua

local utils = require 'lualine.utils.utils'
---------------
-- Constents --
---------------
-- fg and bg must have this much contrast range 0 < contrast_threshold < 0.5
local contrast_threshold = 0.3
-- how much brightness is changed in percentage for light and dark themes
local brightness_modifier_parameter = 10
-- retrives color value from highlight group name in syntax_list
-- first present highlight is returned
local function getHi(scope, syntaxlist)
for _, highlight_name in pairs(syntaxlist) do
if vim.fn.hlexists(highlight_name) ~= 0 then
local color = utils.extract_highlight_colors(highlight_name)
if color.reverse then
if scope == 'bg' then
scope = 'fg'
else
scope = 'bg'
end
end
if color[scope] then return color[scope] end
end
end
return '#000000'
end
-- truns #rrggbb -> { red, green, blue }
local function rgb_str2num(rgb_color_str)
if rgb_color_str:find('#') == 1 then
rgb_color_str = rgb_color_str:sub(2, #rgb_color_str)
end
local red = tonumber(rgb_color_str:sub(1, 2), 16)
local green = tonumber(rgb_color_str:sub(3, 4), 16)
local blue = tonumber(rgb_color_str:sub(5, 6), 16)
return {red = red, green = green, blue = blue}
end
-- turns { red, green, blue } -> #rrggbb
local function rgb_num2str(rgb_color_num)
local rgb_color_str = string.format('#%02x%02x%02x', rgb_color_num.red,
rgb_color_num.green, rgb_color_num.blue)
return rgb_color_str
end
-- returns brightness lavel of color in range 0 to 1
-- arbitary value it's basicaly an weighted average
local function get_color_brightness(rgb_color)
local color = rgb_str2num(rgb_color)
local brightness = (color.red * 2 + color.green * 3 + color.blue) / 6
return brightness / 256
end
-- returns average of colors in range 0 to 1
-- used to ditermine contrast lavel
local function get_color_avg(rgb_color)
local color = rgb_str2num(rgb_color)
return (color.red + color.green + color.blue) / 3 / 256
end
-- clamps the val between left and right
local function clamp(val, left, right)
if val > right then return right end
if val < left then return left end
return val
end
-- changes braghtness of rgb_color by percentage
local function brightness_modifier(rgb_color, parcentage)
local color = rgb_str2num(rgb_color)
color.red = clamp(color.red + (color.red * parcentage / 100), 0, 255)
color.green = clamp(color.green + (color.green * parcentage / 100), 0, 255)
color.blue = clamp(color.blue + (color.blue * parcentage / 100), 0, 255)
return rgb_num2str(color)
end
-- changes contrast of rgb_color by amount
local function contrast_modifier(rgb_color, amount)
local color = rgb_str2num(rgb_color)
color.red = clamp(color.red + amount, 0, 255)
color.green = clamp(color.green + amount, 0, 255)
color.blue = clamp(color.blue + amount, 0, 255)
return rgb_num2str(color)
end
-- Changes brightness of foreground color to achive contrast
-- without changing the color
local function apply_contrast(highlight)
local hightlight_bg_avg = get_color_avg(highlight.bg)
local contrast_threshold_config = clamp(contrast_threshold, 0, 0.5)
local contranst_change_step = 5
if hightlight_bg_avg > .5 then contranst_change_step = -contranst_change_step end
-- donn't waste too much time here max 25 interation should be more than enough
local iteration_count = 1
while (math.abs(get_color_avg(highlight.fg) - hightlight_bg_avg) <
contrast_threshold_config and iteration_count < 25) do
highlight.fg = contrast_modifier(highlight.fg, contranst_change_step)
iteration_count = iteration_count + 1
end
end
-- Get the colors to create theme
local colors = {
normal = getHi('bg', {'PmenuSel', 'PmenuThumb', 'TabLineSel'}),
insert = getHi('fg', {'String', 'MoreMsg'}),
replace = getHi('fg', {'Number', 'Type'}),
visual = getHi('fg', {'Special', 'Boolean', 'Constant'}),
command = getHi('fg', {'Identifier'}),
back1 = getHi('bg', {'Normal', 'StatusLineNC'}),
fore = getHi('fg', {'Normal', 'StatusLine'}),
back2 = getHi('bg', {'StatusLine'})
}
-- Change brightness of colors
-- darken incase of light theme lighten incase of dark theme
local normal_color = utils.extract_highlight_colors('Normal', 'bg')
if normal_color ~= nil then
if get_color_brightness(normal_color) > 0.5 then
brightness_modifier_parameter = -brightness_modifier_parameter
end
for name, color in pairs(colors) do
colors[name] = brightness_modifier(color, brightness_modifier_parameter)
end
end
-- basic theme defination
local M = {
normal = {
a = {bg = colors.normal, fg = colors.back1, gui = 'bold'},
b = {bg = colors.back1, fg = colors.normal},
c = {bg = colors.back2, fg = colors.fore}
},
insert = {
a = {bg = colors.insert, fg = colors.back1, gui = 'bold'},
b = {bg = colors.back1, fg = colors.insert},
c = {bg = colors.back2, fg = colors.fore}
},
replace = {
a = {bg = colors.replace, fg = colors.back1, gui = 'bold'},
b = {bg = colors.back1, fg = colors.replace},
c = {bg = colors.back2, fg = colors.fore}
},
visual = {
a = {bg = colors.visual, fg = colors.back1, gui = 'bold'},
b = {bg = colors.back1, fg = colors.visual},
c = {bg = colors.back2, fg = colors.fore}
},
command = {
a = {bg = colors.command, fg = colors.back1, gui = 'bold'},
b = {bg = colors.back1, fg = colors.command},
c = {bg = colors.back2, fg = colors.fore}
}
}
M.terminal = M.command
M.inactive = M.normal
-- Apply prpper contrast so text is readable
for _, section in pairs(M) do
for _, highlight in pairs(section) do apply_contrast(highlight) end
end
return M