-- Copyright (c) 2020-2021 shadmansaleh -- MIT license, see LICENSE for more details. local require = require('lualine_require').require local highlight = require 'lualine.highlight' local M = require('lualine.utils.class'):extend() -- Used to provide a unique id for each component local component_no = 1 -- variable to store component output for manipulation M.status = '' function M:__tostring() local str = 'Component: ' .. self.options.component_name if self.debug then str = str .. '\n---------------------\n' .. vim.inspect(self) end return str end M.__is_lualine_component = true ---initialize new component ---@param options table options for component function M:init(options) self.options = options or {} component_no = component_no + 1 if not self.options.component_name then self.options.component_name = tostring(component_no) end self.component_no = component_no self:set_separator() self:create_option_highlights() end ---sets the default separator for component based on whether the component ---is in left sections or right sections when separator option is omited. function M:set_separator() if self.options.separator == nil then if self.options.component_separators then if self.options.self.section < 'lualine_x' then self.options.separator = self.options.component_separators.left else self.options.separator = self.options.component_separators.right end end end end ---creates hl group from color option function M:create_option_highlights() -- set custom highlights if self.options.color then self.options.color_highlight = highlight.create_component_highlight_group( self.options.color, self.options.component_name, self.options ) end end ---adds spaces to left and right of a component function M:apply_padding() local padding = self.options.padding local l_padding, r_padding if padding == nil then padding = 1 end if type(padding) == 'number' then l_padding, r_padding = padding, padding elseif type(padding) == 'table' then l_padding, r_padding = padding.left, padding.right end if l_padding then if self.status:find '%%#.*#' == 1 then -- When component has changed the highlight at begining -- we will add the padding after the highlight local pre_highlight = vim.fn.matchlist(self.status, [[\(%#.\{-\}#\)]])[2] self.status = pre_highlight .. string.rep(' ', l_padding) .. self.status:sub(#pre_highlight + 1, #self.status) else self.status = string.rep(' ', l_padding) .. self.status end end if r_padding then self.status = self.status .. string.rep(' ', r_padding) end end ---applies custom highlights for component function M:apply_highlights(default_highlight) if self.options.color_highlight then self.status = highlight.component_format_highlight(self.options.color_highlight) .. self.status end if type(self.options.separator) ~= 'table' and self.status:find '%%#' then -- Apply default highlight only when we aren't applying trans sep and -- the component has changed it's hl. since we won't be applying -- regular sep in those cases so ending with default hl isn't neccessay self.status = self.status .. default_highlight -- Also put it in applied sep so when sep get struped so does the hl self.applied_separator = default_highlight end -- Prepend default hl when the component doesn't start with hl otherwise -- color in previous component can cause side effect if not self.status:find '^%%#' then self.status = default_highlight .. self.status end end ---apply icon in front of component (prepemds component with icon) function M:apply_icon() if self.options.icons_enabled and self.options.icon then self.status = self.options.icon .. ' ' .. self.status end end ---apply separator at end of component only when ---custom highlights haven't affected background function M:apply_separator() local separator = self.options.separator if type(separator) == 'table' then if self.options.separator[2] == '' then if self.options.self.section < 'lualine_x' then separator = self.options.component_separators.left else separator = self.options.component_separators.right end else return end end if separator and #separator > 0 then self.status = self.status .. separator self.applied_separator = self.applied_separator .. separator end end ---apply transitional separator for the component function M:apply_section_separators() if type(self.options.separator) ~= 'table' then return end if self.options.separator.left ~= nil and self.options.separator.left ~= '' then self.status = string.format('%%s{%s}%s', self.options.separator.left, self.status) self.strip_previous_separator = true end if self.options.separator.right ~= nil and self.options.separator.right ~= '' then self.status = string.format('%s%%S{%s}', self.status, self.options.separator.right) end end ---remove separator from tail of this component. ---called by lualine.utils.sections.draw_section to manage unnecessary separators function M:strip_separator() if not self.applied_separator then self.applied_separator = '' end self.status = self.status:sub(1, (#self.status - #self.applied_separator)) self.applied_separator = nil return self.status end -- luacheck: push no unused args ---actual function that updates a component. Must be overwritten with component functionality function M:update_status(is_focused) end -- luacheck: pop ---driver code of the class function M:draw(default_highlight, is_focused) self.status = '' self.applied_separator = '' if self.options.cond ~= nil and self.options.cond() ~= true then return self.status end local status = self:update_status(is_focused) if self.options.fmt then status = self.options.fmt(status or '') end if type(status) == 'string' and #status > 0 then self.status = status self:apply_icon() self:apply_padding() self:apply_highlights(default_highlight) self:apply_section_separators() self:apply_separator() end return self.status end return M