feat: add automatic theme generation (#104)
This commit is contained in:
parent
8624f7c14e
commit
87899eefc5
|
@ -2,6 +2,9 @@
|
|||
|
||||
All available themes are only best effort ports by myself/ other users. If you find a theme to be weird/ wrong please open an issue/ pr.
|
||||
|
||||
### auto
|
||||
if your favourite colorcheme is not yet supported you can use `auto` to make
|
||||
lualine try to match your colorscheme.
|
||||
### 16color
|
||||
![16normal_cropped](https://user-images.githubusercontent.com/41551030/108648240-02d2ae00-74bb-11eb-9ac1-495849621366.png)
|
||||
![16insert_cropped](https://user-images.githubusercontent.com/41551030/108648219-f77f8280-74ba-11eb-84e4-978bf918c21f.png)
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
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 == 'guibg' then scope = 'guifg' else scope = 'guibg' 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( 'guibg', {'PmenuSel', 'PmenuThumb', 'TabLineSel' } ),
|
||||
insert = getHi( 'guifg', {'String', 'MoreMsg' } ),
|
||||
replace = getHi( 'guifg', {'Number', 'Type' } ),
|
||||
visual = getHi( 'guifg', {'Special', 'Boolean', 'Constant' } ),
|
||||
command = getHi( 'guifg', {'Identifier' } ),
|
||||
back1 = getHi( 'guibg', {'Normal', 'StatusLineNC' } ),
|
||||
fore = getHi( 'guifg', {'Normal', 'StatusLine' } ),
|
||||
back2 = getHi( 'guibg', {'StatusLine' } ),
|
||||
}
|
||||
|
||||
|
||||
-- Change brightness of colors
|
||||
-- darken incase of light theme lighten incase of dark theme
|
||||
|
||||
if get_color_brightness(utils.extract_highlight_colors('Normal', 'guibg')) > 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
|
||||
|
||||
-- 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
|
Loading…
Reference in New Issue