diff --git a/lua/lualine/component.lua b/lua/lualine/component.lua index a7877c1..a3330e0 100644 --- a/lua/lualine/component.lua +++ b/lua/lualine/component.lua @@ -1,3 +1,6 @@ +-- Copyright (c) 2020-2021 shadmansaleh +-- MIT license, see LICENSE for more details. + local highlight = require 'lualine.highlight' -- Used to provide a unique id for each component @@ -24,7 +27,7 @@ local Component = { end, 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.self.section < 'lualine_x' then self.options.separator = self.options.component_separators[1] @@ -99,18 +102,41 @@ local Component = { -- Apply separator at end of component only when -- custom highlights haven't affected background apply_separator = function(self) - if self.options.separator and #self.options.separator > 0 then - self.status = self.status .. self.options.separator - self.applied_separator = self.options.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[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, - strip_separator = function(self, default_highlight) - if not default_highlight then default_highlight = '' end + apply_section_separators = function(self) + 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 self.status = self.status:sub(1, (#self.status - - (#self.applied_separator + - #default_highlight))) + (#self.applied_separator))) self.applied_separator = nil return self.status end, @@ -135,6 +161,7 @@ local Component = { self:apply_icon() self:apply_case() self:apply_padding() + self:apply_section_separators() self:apply_highlights(default_highlight) self:apply_separator() end diff --git a/lua/lualine/highlight.lua b/lua/lualine/highlight.lua index 3d63a9f..bd5fdaa 100644 --- a/lua/lualine/highlight.lua +++ b/lua/lualine/highlight.lua @@ -170,7 +170,7 @@ function M.get_transitional_highlights(left_section_data, right_section_data, -- 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('.*%%#(.-)#') + left_highlight_name = left_section_data:match('.*%%#(.-)#.-') else -- When right section us unavailable default to 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 if right_section_data then -- extract highlight_name from %#highlight_name#.... - right_highlight_name = right_section_data:match('%%#(.-)#.*') + right_highlight_name = right_section_data:match('.-%%#(.-)#.*') else -- When right section us unavailable default to 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 if reverse then fg, bg = bg, fg end 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) end return '%#' .. highlight_name .. '#' diff --git a/lua/lualine/init.lua b/lua/lualine/init.lua index 10c252d..4b96525 100644 --- a/lua/lualine/init.lua +++ b/lua/lualine/init.lua @@ -15,12 +15,9 @@ local function statusline(sections, is_focused) for _, section_name in ipairs(section_sequence) do if sections['lualine_' .. section_name] then -- 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( sections['lualine_' .. section_name], - section_highlight) + section_name, is_focused) if #section_data > 0 then table.insert(status_builder, {name = section_name, data = section_data}) @@ -29,6 +26,19 @@ local function statusline(sections, is_focused) end return status_builder 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 local status_builder = create_status_builder() @@ -42,44 +52,47 @@ local function statusline(sections, is_focused) highlight.format_highlight(is_focused, 'lualine_c') .. '%=') half_passed = true end - -- provide section_separators when statusline is in focus - if is_focused then -- component separator needs to have fg = current_section.bg -- and bg = adjacent_section.bg local previous_section = status_builder[i - 1] or {} local current_section = status_builder[i] 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]) + + -- local splited_section = vim.split(current_section.data, '%%s{.-}') + -- if splited_section[1] == '' then table.remove(splited_section, 1) end + local count = 1 + 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 prev or #prev == 0 or count == 1 then prev = previous_section.data end + if prev ~= previous_section.data then + 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 - - -- **( insert the actual section in the middle )** -- - table.insert(status, status_builder[i].data) - - -- For 1st half we need to show separator after section - if current_section.name < 'c' and config.options.section_separators[1] ~= - '' then - local transitional_highlight = highlight.get_transitional_highlights( - current_section.data, - next_section.data) - if transitional_highlight and config.options.section_separators and - config.options.section_separators[1] then - table.insert(status, transitional_highlight .. - config.options.section_separators[1]) - end - end - else -- when not in focus - table.insert(status, status_builder[i].data) - end + count = 1 + 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 + count = count+4+#sep + end + table.insert(status, current_section.data) end -- incase none of x,y,z was configured lets not fill whole statusline with a,b,c section if not half_passed then diff --git a/lua/lualine/utils/section.lua b/lua/lualine/utils/section.lua index f8a12f8..24bb7d7 100644 --- a/lua/lualine/utils/section.lua +++ b/lua/lualine/utils/section.lua @@ -2,8 +2,12 @@ -- MIT license, see LICENSE for more details. local M = {} local utils = require('lualine.utils.utils') +local highlight = require('lualine.highlight') -- 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 = {} for _, component in pairs(section) do -- load components into status table @@ -15,29 +19,52 @@ function M.draw_section(section, highlight_name) end -- 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 first_component_no = #section -- Check through components to see when component separator need to be removed 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 if not last_component_found and #status[component_no] > 0 then last_component_found = true - status[component_no] = section[component_no]:strip_separator( - highlight_name) + status[component_no] = section[component_no]:strip_separator() + 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 -- Remove component separator when color option is used in next component - if next_component_colored then - next_component_colored = false + if strip_next_component then + strip_next_component = false status[component_no] = section[component_no]:strip_separator() end -- Remove component separator when color option is used to color background if (type(section[component_no].options.color) == 'table' and section[component_no].options.color.bg) or type(section[component_no].options.color) == 'string' then - next_component_colored = true + strip_next_component = true status[component_no] = section[component_no]:strip_separator() 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 -- 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 return status_str else - return highlight_name .. status_str + return left_sparator_string .. highlight_name .. status_str end end diff --git a/lua/tests/spec/utils_spec.lua b/lua/tests/spec/utils_spec.lua index d207be6..f290edb 100644 --- a/lua/tests/spec/utils_spec.lua +++ b/lua/tests/spec/utils_spec.lua @@ -71,19 +71,29 @@ end) describe('Section genarator', function() local sec = require 'lualine.utils.section' it('can draw', function() - local opts = build_component_opts() + local opts = build_component_opts({section_separators = {'', ''}}) local section = { 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) 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_colored2 = build_component_opts({color = {bg = '#223344'}}) - local opts_colored3 = build_component_opts({color = {fg = '#223344'}}) + local opts_colored2 = build_component_opts( + { + color = {bg = '#223344'}, + section_separators = {'', ''} + }) + local opts_colored3 = build_component_opts( + { + color = {fg = '#223344'}, + section_separators = {'', ''} + }) require'lualine.highlight'.create_highlight_groups( require 'lualine.themes.gruvbox') local section = { @@ -92,21 +102,29 @@ describe('Section genarator', function() require('lualine.components.special.function_component'):new(opts) } -- Removes separator on string color - eq('%#MyHl# test %#MyHl#%#MyColor# test %#MyHl# test ', - sec.draw_section(section, '%#MyHl#')) - section[2] = require('lualine.components.special.function_component'):new( - opts_colored2) + eq( + '%#lualine_MySection_normal# test %#lualine_MySection_normal#%#MyColor#' + .. ' 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) local highlight_name = '%#lualine_c_' .. section[2].options.component_name .. '_normal#' -- Removes separator on color with bg - eq('%#MyHl# test %#MyHl#' .. highlight_name .. ' test %#MyHl# test ', - sec.draw_section(section, '%#MyHl#')) - section[2] = require('lualine.components.special.function_component'):new( - opts_colored3) + eq('%#lualine_MySection_normal# test %#lualine_MySection_normal#' .. + highlight_name .. + ' 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) local highlight_name2 = '%#lualine_c_' .. section[2].options.component_name .. '_normal#' -- Doesn't remove separator on color without bg - eq('%#MyHl# test %#MyHl#' .. highlight_name2 .. ' test %#MyHl# test ', - sec.draw_section(section, '%#MyHl#')) + eq('%#lualine_MySection_normal# test %#lualine_MySection_normal#' .. + highlight_name2 .. + ' test %#lualine_MySection_normal# test %#lualine_MySection_normal#', + sec.draw_section(section, 'MySection')) end) end)