Allow transitional separator to be set as component option

This commit is contained in:
shadmansaleh 2021-05-07 06:54:49 +06:00
parent 0411f1c830
commit f480db58fb
5 changed files with 154 additions and 68 deletions

View File

@ -1,3 +1,6 @@
-- Copyright (c) 2020-2021 shadmansaleh
-- MIT license, see LICENSE for more details.
local highlight = require 'lualine.highlight' local highlight = require 'lualine.highlight'
-- Used to provide a unique id for each component -- Used to provide a unique id for each component
@ -24,7 +27,7 @@ local Component = {
end, end,
set_separator = function(self) set_separator = function(self)
if type(self.options.separator) ~= 'string' then if self.options.separator == nil then
if self.options.component_separators then if self.options.component_separators then
if self.options.self.section < 'lualine_x' then if self.options.self.section < 'lualine_x' then
self.options.separator = self.options.component_separators[1] self.options.separator = self.options.component_separators[1]
@ -99,18 +102,41 @@ local Component = {
-- Apply separator at end of component only when -- Apply separator at end of component only when
-- custom highlights haven't affected background -- custom highlights haven't affected background
apply_separator = function(self) apply_separator = function(self)
if self.options.separator and #self.options.separator > 0 then local separator = self.options.separator
self.status = self.status .. self.options.separator if type(separator) == 'table' then
self.applied_separator = self.options.separator if self.options.separator[2] == '' then
if self.options.self.section < 'lualine_x' then
separator = self.options.component_separators[1]
else
separator = self.options.component_separators[2]
end
else
return
end
end
if separator and #separator > 0 then
self.status = self.status .. separator
self.applied_separator = separator
end end
end, end,
strip_separator = function(self, default_highlight) apply_section_separators = function(self)
if not default_highlight then default_highlight = '' end if type(self.options.separator) ~= 'table' then return end
if self.options.separator[1] ~= '' then
self.status = string.format('%%s{%s}%s', self.options.separator[1],
self.status)
self.strip_previous_separator = true
end
if self.options.separator[2] ~= '' then
self.status = string.format('%s%%S{%s}', self.status,
self.options.separator[2])
end
end,
strip_separator = function(self)
if not self.applied_separator then self.applied_separator = '' end if not self.applied_separator then self.applied_separator = '' end
self.status = self.status:sub(1, (#self.status - self.status = self.status:sub(1, (#self.status -
(#self.applied_separator + (#self.applied_separator)))
#default_highlight)))
self.applied_separator = nil self.applied_separator = nil
return self.status return self.status
end, end,
@ -135,6 +161,7 @@ local Component = {
self:apply_icon() self:apply_icon()
self:apply_case() self:apply_case()
self:apply_padding() self:apply_padding()
self:apply_section_separators()
self:apply_highlights(default_highlight) self:apply_highlights(default_highlight)
self:apply_separator() self:apply_separator()
end end

View File

@ -170,7 +170,7 @@ function M.get_transitional_highlights(left_section_data, right_section_data,
-- Grab the last highlighter of left section -- Grab the last highlighter of left section
if left_section_data then if left_section_data then
-- extract highlight_name from .....%#highlight_name# -- extract highlight_name from .....%#highlight_name#
left_highlight_name = left_section_data:match('.*%%#(.-)#') left_highlight_name = left_section_data:match('.*%%#(.-)#.-')
else else
-- When right section us unavailable default to lualine_c -- When right section us unavailable default to lualine_c
left_highlight_name = append_mode('lualine_c') left_highlight_name = append_mode('lualine_c')
@ -180,7 +180,7 @@ function M.get_transitional_highlights(left_section_data, right_section_data,
end end
if right_section_data then if right_section_data then
-- extract highlight_name from %#highlight_name#.... -- extract highlight_name from %#highlight_name#....
right_highlight_name = right_section_data:match('%%#(.-)#.*') right_highlight_name = right_section_data:match('.-%%#(.-)#.*')
else else
-- When right section us unavailable default to lualine_c -- When right section us unavailable default to lualine_c
right_highlight_name = append_mode('lualine_c') right_highlight_name = append_mode('lualine_c')
@ -210,6 +210,7 @@ function M.get_transitional_highlights(left_section_data, right_section_data,
-- be placed before section -- be placed before section
if reverse then fg, bg = bg, fg end if reverse then fg, bg = bg, fg end
if not fg or not bg then return '' end -- Color retrieval failed if not fg or not bg then return '' end -- Color retrieval failed
if bg == fg then return '' end -- Separatoe won't be visible anyway
M.highlight(highlight_name, fg, bg) M.highlight(highlight_name, fg, bg)
end end
return '%#' .. highlight_name .. '#' return '%#' .. highlight_name .. '#'

View File

@ -15,12 +15,9 @@ local function statusline(sections, is_focused)
for _, section_name in ipairs(section_sequence) do for _, section_name in ipairs(section_sequence) do
if sections['lualine_' .. section_name] then if sections['lualine_' .. section_name] then
-- insert highlight+components of this section to status_builder -- insert highlight+components of this section to status_builder
local section_highlight = highlight.format_highlight(is_focused,
'lualine_' ..
section_name)
local section_data = utils_section.draw_section( local section_data = utils_section.draw_section(
sections['lualine_' .. section_name], sections['lualine_' .. section_name],
section_highlight) section_name, is_focused)
if #section_data > 0 then if #section_data > 0 then
table.insert(status_builder, table.insert(status_builder,
{name = section_name, data = section_data}) {name = section_name, data = section_data})
@ -29,6 +26,19 @@ local function statusline(sections, is_focused)
end end
return status_builder return status_builder
end end
local function fill_section_separator(prev, next, sep, reverse)
if #sep == 0 then return 0 end
local transitional_highlight = highlight.get_transitional_highlights(
prev, next, reverse)
-- if not transitional_highlight or #transitional_highlight == 0 then
-- end
if transitional_highlight and #transitional_highlight > 0 then
return transitional_highlight..sep
else
return ''
end
end
-- status_builder stores statusline without section_separators -- status_builder stores statusline without section_separators
local status_builder = create_status_builder() local status_builder = create_status_builder()
@ -42,44 +52,47 @@ local function statusline(sections, is_focused)
highlight.format_highlight(is_focused, 'lualine_c') .. '%=') highlight.format_highlight(is_focused, 'lualine_c') .. '%=')
half_passed = true half_passed = true
end end
-- provide section_separators when statusline is in focus
if is_focused then
-- component separator needs to have fg = current_section.bg -- component separator needs to have fg = current_section.bg
-- and bg = adjacent_section.bg -- and bg = adjacent_section.bg
local previous_section = status_builder[i - 1] or {} local previous_section = status_builder[i - 1] or {}
local current_section = status_builder[i] local current_section = status_builder[i]
local next_section = status_builder[i + 1] or {} local next_section = status_builder[i + 1] or {}
-- For 2nd half we need to show separator before section
if current_section.name > 'x' and config.options.section_separators[2] ~=
'' then
local transitional_highlight = highlight.get_transitional_highlights(
previous_section.data,
current_section.data, true)
if transitional_highlight and config.options.section_separators and
config.options.section_separators[2] then
table.insert(status, transitional_highlight ..
config.options.section_separators[2])
end
end
-- **( insert the actual section in the middle )** -- -- local splited_section = vim.split(current_section.data, '%%s{.-}')
table.insert(status, status_builder[i].data) -- if splited_section[1] == '' then table.remove(splited_section, 1) end
local count = 1
-- For 1st half we need to show separator after section while count do
if current_section.name < 'c' and config.options.section_separators[1] ~= local sep = current_section.data:match('%%s{(.-)}', count)
'' then if not sep then break end
local transitional_highlight = highlight.get_transitional_highlights( count = current_section.data:find('%%s{.-}', count)
current_section.data, if not count then break end
next_section.data) local prev = current_section.data:sub(1, count - 1)
if transitional_highlight and config.options.section_separators and local nxt = current_section.data:sub(count+4+#sep)
config.options.section_separators[1] then if not prev or #prev == 0 or count == 1 then prev = previous_section.data end
table.insert(status, transitional_highlight .. if prev ~= previous_section.data then
config.options.section_separators[1]) local last_hl = prev:match('.*%#(.-)#.-')
current_section.data = prev .. fill_section_separator(prev, nxt, sep, false)..'%#'..last_hl..'#'..nxt
else
current_section.data = fill_section_separator(prev, nxt, sep, true)..nxt
end end
end end
else -- when not in focus count = 1
table.insert(status, status_builder[i].data) while count do
local sep = current_section.data:match('%%S{(.-)}', count)
if not sep then break end
count = current_section.data:find('%%S{.-}', count)
if not count then break end
local prev = current_section.data:sub(1, count - 1)
local nxt = current_section.data:sub(count+4+#sep)
if not nxt or #nxt == 0 or count == #current_section.data then nxt = next_section.data end
if nxt ~= next_section.data then
current_section.data = prev .. fill_section_separator(prev, nxt, sep, false)..nxt
else
current_section.data = prev .. fill_section_separator(prev, nxt, sep, false)
end end
count = count+4+#sep
end
table.insert(status, current_section.data)
end end
-- incase none of x,y,z was configured lets not fill whole statusline with a,b,c section -- incase none of x,y,z was configured lets not fill whole statusline with a,b,c section
if not half_passed then if not half_passed then

View File

@ -2,8 +2,12 @@
-- MIT license, see LICENSE for more details. -- MIT license, see LICENSE for more details.
local M = {} local M = {}
local utils = require('lualine.utils.utils') local utils = require('lualine.utils.utils')
local highlight = require('lualine.highlight')
-- Returns formated string for a section -- Returns formated string for a section
function M.draw_section(section, highlight_name) function M.draw_section(section, section_name, is_focused)
local highlight_name = highlight.format_highlight(is_focused,
'lualine_'..section_name)
local status = {} local status = {}
for _, component in pairs(section) do for _, component in pairs(section) do
-- load components into status table -- load components into status table
@ -15,29 +19,52 @@ function M.draw_section(section, highlight_name)
end end
-- Flags required for knowing when to remove component separator -- Flags required for knowing when to remove component separator
local next_component_colored = false local strip_next_component = false
local last_component_found = false local last_component_found = false
local first_component_no = #section
-- Check through components to see when component separator need to be removed -- Check through components to see when component separator need to be removed
for component_no = #section, 1, -1 do for component_no = #section, 1, -1 do
if #status[component_no] > 0 then
first_component_no = component_no
end
-- Remove component separator with highlight for last component -- Remove component separator with highlight for last component
if not last_component_found and #status[component_no] > 0 then if not last_component_found and #status[component_no] > 0 then
last_component_found = true last_component_found = true
status[component_no] = section[component_no]:strip_separator( status[component_no] = section[component_no]:strip_separator()
highlight_name) if section_name < 'c' then
if type(section[first_component_no].options.separator) ~= 'table' and
section[1].options.section_separators[1] ~= '' then
status[component_no] = string.format('%s%%S{%s}',status[component_no],
section[1].options.section_separators[1])
end
end
end end
-- Remove component separator when color option is used in next component -- Remove component separator when color option is used in next component
if next_component_colored then if strip_next_component then
next_component_colored = false strip_next_component = false
status[component_no] = section[component_no]:strip_separator() status[component_no] = section[component_no]:strip_separator()
end end
-- Remove component separator when color option is used to color background -- Remove component separator when color option is used to color background
if (type(section[component_no].options.color) == 'table' and if (type(section[component_no].options.color) == 'table' and
section[component_no].options.color.bg) or section[component_no].options.color.bg) or
type(section[component_no].options.color) == 'string' then type(section[component_no].options.color) == 'string' then
next_component_colored = true strip_next_component = true
status[component_no] = section[component_no]:strip_separator() status[component_no] = section[component_no]:strip_separator()
end end
if (section[component_no].strip_previous_separator == true) then
strip_next_component = true
end
end
local left_sparator_string = ''
if section_name > 'x' and section[first_component_no] and
type(section[first_component_no].options.separator) ~= 'table' and
section[1].options.section_separators[2] ~= '' then
left_sparator_string = string.format('%%s{%s}',
section[first_component_no].options.ls_separator or
section[1].options.section_separators[2])
end end
-- Remove empty strings from status -- Remove empty strings from status
@ -47,7 +74,7 @@ function M.draw_section(section, highlight_name)
-- Don't prepend with old highlight when the component changes it imidiately -- Don't prepend with old highlight when the component changes it imidiately
return status_str return status_str
else else
return highlight_name .. status_str return left_sparator_string .. highlight_name .. status_str
end end
end end

View File

@ -71,19 +71,29 @@ end)
describe('Section genarator', function() describe('Section genarator', function()
local sec = require 'lualine.utils.section' local sec = require 'lualine.utils.section'
it('can draw', function() it('can draw', function()
local opts = build_component_opts() local opts = build_component_opts({section_separators = {'', ''}})
local section = { local section = {
require('lualine.components.special.function_component'):new(opts), require('lualine.components.special.function_component'):new(opts),
require('lualine.components.special.function_component'):new(opts) require('lualine.components.special.function_component'):new(opts)
} }
eq('%#MyHl# test %#MyHl# test ', sec.draw_section(section, '%#MyHl#')) eq(
'%#lualine_MySection_normal# test %#lualine_MySection_normal# test %#lualine_MySection_normal#',
sec.draw_section(section, 'MySection'))
end) end)
it('can remove separators from component with custom colors', function() it('can remove separators from component with custom colors', function()
local opts = build_component_opts() local opts = build_component_opts({section_separators = {'', ''}})
local opts_colored = build_component_opts({color = 'MyColor'}) local opts_colored = build_component_opts({color = 'MyColor'})
local opts_colored2 = build_component_opts({color = {bg = '#223344'}}) local opts_colored2 = build_component_opts(
local opts_colored3 = build_component_opts({color = {fg = '#223344'}}) {
color = {bg = '#223344'},
section_separators = {'', ''}
})
local opts_colored3 = build_component_opts(
{
color = {fg = '#223344'},
section_separators = {'', ''}
})
require'lualine.highlight'.create_highlight_groups( require'lualine.highlight'.create_highlight_groups(
require 'lualine.themes.gruvbox') require 'lualine.themes.gruvbox')
local section = { local section = {
@ -92,21 +102,29 @@ describe('Section genarator', function()
require('lualine.components.special.function_component'):new(opts) require('lualine.components.special.function_component'):new(opts)
} }
-- Removes separator on string color -- Removes separator on string color
eq('%#MyHl# test %#MyHl#%#MyColor# test %#MyHl# test ', eq(
sec.draw_section(section, '%#MyHl#')) '%#lualine_MySection_normal# test %#lualine_MySection_normal#%#MyColor#'
section[2] = require('lualine.components.special.function_component'):new( .. ' test %#lualine_MySection_normal# test %#lualine_MySection_normal#',
sec.draw_section(section, 'MySection'))
section[2] =
require('lua.lualine.components.special.function_component'):new(
opts_colored2) opts_colored2)
local highlight_name = local highlight_name =
'%#lualine_c_' .. section[2].options.component_name .. '_normal#' '%#lualine_c_' .. section[2].options.component_name .. '_normal#'
-- Removes separator on color with bg -- Removes separator on color with bg
eq('%#MyHl# test %#MyHl#' .. highlight_name .. ' test %#MyHl# test ', eq('%#lualine_MySection_normal# test %#lualine_MySection_normal#' ..
sec.draw_section(section, '%#MyHl#')) highlight_name ..
section[2] = require('lualine.components.special.function_component'):new( ' test %#lualine_MySection_normal# test %#lualine_MySection_normal#',
sec.draw_section(section, 'MySection'))
section[2] =
require('lua.lualine.components.special.function_component'):new(
opts_colored3) opts_colored3)
local highlight_name2 = local highlight_name2 =
'%#lualine_c_' .. section[2].options.component_name .. '_normal#' '%#lualine_c_' .. section[2].options.component_name .. '_normal#'
-- Doesn't remove separator on color without bg -- Doesn't remove separator on color without bg
eq('%#MyHl# test %#MyHl#' .. highlight_name2 .. ' test %#MyHl# test ', eq('%#lualine_MySection_normal# test %#lualine_MySection_normal#' ..
sec.draw_section(section, '%#MyHl#')) highlight_name2 ..
' test %#lualine_MySection_normal# test %#lualine_MySection_normal#',
sec.draw_section(section, 'MySection'))
end) end)
end) end)