lualine.nvim/lua/lualine/highlight.lua

229 lines
9.1 KiB
Lua
Raw Normal View History

-- Copyright (c) 2020-2021 hoob3rt
-- MIT license, see LICENSE for more details.
2020-12-30 14:48:51 +00:00
local M = { }
local utils_colors = require "lualine.utils.cterm_colors"
local utils = require 'lualine.utils.utils'
local section_highlight_map = {x = 'c', y = 'b', z = 'a'}
local loaded_highlights = {}
-- @description: clears Highlights in loaded_highlights
function M.clear_highlights()
for no, highlight_name in ipairs(loaded_highlights)do
if highlight_name and #highlight_name > 0 and utils.highlight_exists(highlight_name) then
vim.cmd('highlight clear ' .. highlight_name)
end
loaded_highlights[no] = nil
end
end
2020-12-30 14:48:51 +00:00
local function highlight (name, foreground, background, gui)
local command = { 'highlight', name, }
if foreground then
table.insert(command, 'ctermfg=' .. (foreground[2] or
(foreground ~= 'none' and utils_colors.get_cterm_color(foreground)) or 'none'))
table.insert(command, 'guifg=' .. (foreground[1] or foreground))
end
if background then
table.insert(command, 'ctermbg=' .. (background[2] or
(background ~= 'none' and utils_colors.get_cterm_color(background)) or 'none'))
table.insert(command, 'guibg=' .. (background[1] or background))
end
if gui then
table.insert(command, 'cterm=' .. (gui or 'none'))
table.insert(command, 'gui=' .. (gui or 'none'))
end
vim.cmd(table.concat(command, ' '))
table.insert(loaded_highlights, name)
2020-12-30 14:48:51 +00:00
end
local function apply_defaults_to_theme(theme)
local modes = {'insert', 'visual', 'replace', 'command', 'terminal', 'inactive'}
for _, mode in ipairs(modes) do
if not theme[mode] then
theme[mode] = theme['normal']
else
for section_name, section in pairs(theme['normal']) do
theme[mode][section_name] = (theme[mode][section_name] or section)
end
end
end
return theme
end
function M.create_highlight_groups(theme)
apply_defaults_to_theme(theme)
2020-12-30 14:48:51 +00:00
for mode, sections in pairs(theme) do
for section, colorscheme in pairs(sections) do
local highlight_group_name = { 'lualine', section, mode }
highlight(table.concat(highlight_group_name, '_'), colorscheme.fg, colorscheme.bg, colorscheme.gui)
2020-12-30 14:48:51 +00:00
end
end
end
-- @description: adds '_mode' at end of highlight_group
-- @param highlight_group:(string) name of highlight group
-- @return: (string) highlight group name with mode
local function append_mode(highlight_group)
2020-12-30 14:48:51 +00:00
local mode = require('lualine.components.mode')()
if mode == 'VISUAL' or mode == 'V-BLOCK' or mode == 'V-LINE'
or mode == 'SELECT' or mode == 'S-LINE' or mode == 'S-BLOCK'then
highlight_group = highlight_group .. '_visual'
elseif mode == 'REPLACE' or mode == 'V-REPLACE' then
highlight_group = highlight_group .. '_replace'
elseif mode == 'INSERT' then
highlight_group = highlight_group .. '_insert'
elseif mode == 'COMMAND' or mode == 'EX' or mode == 'MORE' or mode == 'CONFIRM'then
highlight_group = highlight_group .. '_command'
elseif mode == 'TERMINAL' then
highlight_group = highlight_group .. '_terminal'
else
highlight_group = highlight_group .. '_normal'
end
return highlight_group
end
-- Create highlight group with fg bg and gui from theme
-- section and theme are extracted from @options.self table
-- @@color has to be { fg = "#rrggbb", bg="#rrggbb" gui = "effect" }
-- all the color elements are optional if fg or bg is not given options must be provided
-- So fg and bg can default the themes colors
-- @@highlight_tag is unique tag for highlight group
-- returns the name of highlight group
-- @@options is parameter of component.init() function
-- @return: (string) unique name that can be used by component_format_highlight
-- to retrive highlight group
function M.create_component_highlight_group(color , highlight_tag, options)
if color.bg and color.fg then
-- When bg and fg are both present we donn't need to set highlighs for
-- each mode as they will surely look the same. So we can work without options
local highlight_group_name = table.concat({ 'lualine', highlight_tag, 'no_mode'}, '_')
highlight(highlight_group_name, color.fg, color.bg, color.gui)
return highlight_group_name
end
local modes = {'normal', 'insert', 'visual', 'replace', 'command', 'terminal', 'inactive'}
local normal_hl
-- convert lualine_a -> a before setting section
local section = options.self.section:match('lualine_(.*)')
if section > 'c' then
section = section_highlight_map[section]
end
for _, mode in ipairs(modes) do
local highlight_group_name = { options.self.section, highlight_tag, mode }
local default_color_table = options.theme[mode] and
options.theme[mode][section] or options.theme.normal[section]
local bg = (color.bg or default_color_table.bg)
local fg = (color.fg or default_color_table.fg)
-- Check if it's same as normal mode if it is no need to create aditional highlight
if mode ~= 'normal' then
if bg ~= normal_hl.bg and fg ~= normal_hl.fg then
highlight(table.concat(highlight_group_name, '_'), fg, bg, color.gui)
end
else
normal_hl = {bg = bg, fg = fg}
highlight(table.concat(highlight_group_name, '_'), fg, bg, color.gui)
end
end
return options.self.section..'_'..highlight_tag
end
-- @description: retrieve highlight_groups for components
-- @param highlight_name:(string) highlight group name without mode
-- return value of create_component_highlight_group is to be passed in
-- this parameter to receive highlight that was created
-- @return: (string) formated highlight group name
function M.component_format_highlight(highlight_name)
local highlight_group = highlight_name
if highlight_name:find('no_mode') == #highlight_name - #'no_mode' + 1 then
return '%#'..highlight_group..'#'
end
if vim.g.statusline_winid == vim.fn.win_getid() then
highlight_group = append_mode(highlight_group)
else
highlight_group = highlight_group..'_inactive'
end
if utils.highlight_exists(highlight_group)then
return '%#'..highlight_group..'#'
else
return '%#'..highlight_name..'_normal#'
end
end
function M.format_highlight(is_focused, highlight_group)
if highlight_group > 'lualine_c' then
highlight_group = 'lualine_' .. section_highlight_map[highlight_group:match('lualine_(.)')]
end
local highlight_name = highlight_group
if not is_focused then
return '%#' .. highlight_group .. [[_inactive#]]
2020-12-30 14:48:51 +00:00
else
highlight_name = append_mode(highlight_group)
2020-12-30 14:48:51 +00:00
end
return '%#' .. highlight_name ..'#'
end
-- @description : Provides transitional highlights for section separators.
-- @param left_section_data :(string) section before separator
-- @param right_section_data:(string) section after separator
-- @param reverse :(string) Whether it's a left separator or right separator
-- '▶️' and '◀️' needs reverse colors so this parameter needs to be set true.
-- @return: (string) formated highlight group name
function M.get_transitional_highlights(left_section_data, right_section_data, reverse )
local left_highlight_name, right_highlight_name
-- Grab the last highlighter of left section
if left_section_data then
-- extract highlight_name from .....%#highlight_name#
left_highlight_name = left_section_data:match('.*%%#(.*)#')
else
-- When right section us unavailable default to lualine_c
left_highlight_name = append_mode('lualine_c')
if not utils.highlight_exists(left_highlight_name) then
left_highlight_name = 'lualine_c_normal'
end
end
if right_section_data then
-- using vim-regex cause lua-paterns don't have non-greedy matching
-- extract highlight_name from %#highlight_name#....
right_highlight_name = vim.fn.matchlist(right_section_data, [[%#\(.\{-\}\)#]])[2]
else
-- When right section us unavailable default to lualine_c
right_highlight_name = append_mode('lualine_c')
if not utils.highlight_exists(right_highlight_name) then
right_highlight_name = 'lualine_c_normal'
end
end
-- When both left and right highlights are same nothing to transition to
if left_highlight_name == right_highlight_name then return end
-- construct the name of hightlight group
local highlight_name
if left_highlight_name:find('lualine_') == 1 then
highlight_name = left_highlight_name .. '_to_' .. right_highlight_name
else
highlight_name = 'lualine_' .. left_highlight_name .. '_to_' .. right_highlight_name
end
if not utils.highlight_exists(highlight_name) then
-- Create the highlight_group if needed
local function set_transitional_highlights()
-- Get colors from highlights
-- using string.format to convert decimal to hexadecimal
local fg = utils.extract_highlight_colors(left_highlight_name, 'guibg')
local bg = utils.extract_highlight_colors(right_highlight_name, 'guibg')
if not fg then fg = 'none' end
if not bg then bg = 'none' end
-- swap the bg and fg when reverse is true. As in that case highlight will
-- be placed before section
if reverse then fg, bg = bg, fg end
highlight(highlight_name, fg, bg)
end
-- Create highlights and setup to survive colorscheme changes
set_transitional_highlights()
utils.expand_set_theme(set_transitional_highlights)
end
return '%#' .. highlight_name .. '#'
2020-12-30 14:48:51 +00:00
end
return M