-- Copyright (c) 2020-2021 hoob3rt -- MIT license, see LICENSE for more details. local utils = require('lualine.utils.utils') local utils_section = require('lualine.utils.section') local highlight = require('lualine.highlight') local config = require('lualine.defaults') local M = {} local function apply_configuration(config_table) if not config_table then return end local function parse_sections(section_group_name) if not config_table[section_group_name] then return end for section_name, section in pairs(config_table[section_group_name]) do config[section_group_name][section_name] = config_table[section_group_name][section_name] if type(section) == 'table' then for _, component in pairs(section) do if type(component) == 'table' and type(component[2]) == 'table' then local options = component[2] component[2] = nil for key, val in pairs(options) do component[key] = val end end end end end end parse_sections('options') parse_sections('sections') parse_sections('inactive_sections') parse_sections('tabline') if config_table.extensions then config.extensions = config_table.extensions end end local function check_single_separator() local compoennt_separator = config.options.component_separators local section_separator = config.options.section_separators if config.options.component_separators ~= nil then if type(config.options.component_separators) == 'string' then config.options.component_separators = {compoennt_separator, compoennt_separator} elseif #config.options.component_separators == 1 then config.options.component_separators = { config.options.component_separators[1], config.options.component_separators[1] } end end if config.options.section_separators ~= nil then if type(config.options.section_separators) == 'string' then config.options.section_separators = {section_separator, section_separator} elseif #config.options.section_separators == 1 then config.options.section_separators = { config.options.section_separators[1], config.options.section_separators[1] } end end end local function load_special_components(component) return function() -- precedence lualine_component > vim_var > lua_var > vim_function if component:find('[gvtwb]?o?:') == 1 then -- vim veriable component -- accepts g:, v:, t:, w:, b:, o, go:, vo:, to:, wo:, bo: -- filters g portion from g:var local scope = component:match('[gvtwb]?o?') -- filters var portion from g:var -- For some reason overwriting component var from outer scope causes the -- component not to work . So creating a new local name component to use:/ local component = component:sub(#scope + 2, #component) -- Displays nothing when veriable aren't present local return_val = vim[scope][component] if return_val == nil then return '' end local ok ok, return_val = pcall(tostring, return_val) if ok then return return_val end return '' elseif loadstring(string.format('return %s ~= nil', component)) and loadstring(string.format([[return %s ~= nil]], component))() then -- lua veriable component return loadstring(string.format([[ local ok, return_val = pcall(tostring, %s) if ok then return return_val end return '']], component))() else -- vim function component local ok, return_val = pcall(vim.fn[component]) if not ok then return '' end -- function call failed ok, return_val = pcall(tostring, return_val) if ok then return return_val else return '' end end end end local function component_loader(component) if type(component[1]) == 'function' then return component end if type(component[1]) == 'string' then -- Keep component name for later use as component[1] will be overwritten -- With component function component.component_name = component[1] -- apply default args for opt_name, opt_val in pairs(config.options) do if component[opt_name] == nil then component[opt_name] = opt_val end end -- load the component local ok, loaded_component = pcall(require, 'lualine.components.' .. component.component_name) if not ok then loaded_component = load_special_components(component.component_name) end component[1] = loaded_component if type(component[1]) == 'table' then component[1] = component[1].init(component) end -- set custom highlights if component.color then local function update_color() component.color_highlight = highlight.create_component_highlight_group( component.color, component.component_name, component) end update_color() utils.expand_set_theme(update_color) end end end local function load_sections(sections) for section_name, section in pairs(sections) do for index, component in pairs(section) do if type(component) == 'string' or type(component) == 'function' then component = {component} end component.self = {} component.self.section = section_name component_loader(component) section[index] = component end end end local function load_components() load_sections(config.sections) load_sections(config.inactive_sections) load_sections(config.tabline) end local function load_extensions() for index, extension in pairs(config.extensions) do local local_extension = require('lualine.extensions.' .. extension) load_sections(local_extension.sections) load_sections(local_extension.inactive_sections) config.extensions[index] = local_extension end end local function lualine_set_theme() if type(config.options.theme) == 'string' then config.options.theme = require('lualine.themes.' .. config.options.theme) -- change the theme table in component so their custom -- highlights can reflect theme change local function reset_component_theme(sections) for _, section in pairs(sections) do for _, component in pairs(section) do if type(component) == 'table' then component.theme = config.options.theme end end end end reset_component_theme(config.sections) reset_component_theme(config.inactive_sections) end utils.clear_highlights() highlight.create_highlight_groups(config.options.theme) end local function statusline(sections, is_focused) local function create_status_builder() -- The sequence sections should maintain local section_sequence = {'a', 'b', 'c', 'x', 'y', 'z'} local status_builder = {} 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) if #section_data > 0 then table.insert(status_builder, {name = section_name, data = section_data}) end end end return status_builder end -- status_builder stores statusline without section_separators local status_builder = create_status_builder() -- Actual statusline local status = {} local half_passed = false for i = 1, #status_builder do -- midsection divider if not half_passed and status_builder[i].name > 'c' then table.insert(status, 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' 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 )** -- table.insert(status, status_builder[i].data) -- For 1st half we need to show separator after section if current_section.name < 'c' 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 end -- incase none of x,y,z was configured lets not fill whole statusline with a,b,c section if not half_passed then table.insert(status, highlight.format_highlight(is_focused, 'lualine_c') .. '%=') end return table.concat(status) end -- check if any extension matches the filetype and return proper sections local function get_extension_sections() local sections, inactive_sections = nil, nil for _, extension in ipairs(config.extensions) do for _, filetype in ipairs(extension.filetypes) do if vim.bo.filetype == filetype then sections = extension.sections inactive_sections = extension.inactive_sections break end end end return {sections = sections, inactive_sections = inactive_sections} end local function status_dispatch() local extension_sections = get_extension_sections() if vim.g.statusline_winid == vim.fn.win_getid() then local sections = extension_sections.sections if sections == nil then sections = config.sections end return statusline(sections, true) else local inactive_sections = extension_sections.inactive_sections if inactive_sections == nil then inactive_sections = config.inactive_sections end return statusline(inactive_sections, false) end end local function tabline() return statusline(config.tabline, true) end local function setup_theme() lualine_set_theme() _G.lualine_set_theme = lualine_set_theme vim.api.nvim_exec([[ augroup lualine autocmd! autocmd ColorScheme * call v:lua.lualine_set_theme() augroup END ]], false) end local function set_tabline() if next(config.tabline) ~= nil then _G.lualine_tabline = tabline vim.o.tabline = '%!v:lua.lualine_tabline()' vim.o.showtabline = 2 end end local function set_statusline() if next(config.sections) ~= nil or next(config.inactive_sections) ~= nil then _G.lualine_statusline = status_dispatch vim.o.statusline = '%!v:lua.lualine_statusline()' vim.api.nvim_exec([[ autocmd lualine WinLeave,BufLeave * lua vim.wo.statusline=lualine_statusline() autocmd lualine WinEnter,BufEnter * setlocal statusline=%!v:lua.lualine_statusline() ]], false) end end function M.setup(user_config) if M.options ~= nil or M.sections ~= nil or M.inactive_sections ~= nil or M.tabline ~= nil or M.extensions ~= nil then if vim.api.nvim_echo then vim.api.nvim_echo({ { 'lualine.nvim: lualine is moving to setup function to be consistent with other lua plugins, all other configuration options will be removed by 24.03.2021, please change your configuration(example in readme)', 'WarningMsg' } }, true, {}) else print( 'lualine.nvim: lualine is moving to setup function to be consistent with other lua plugins, all other configuration options will be removed by 24.03.2021, please change your configuration(example in readme)') end if M.options ~= nil then user_config.options = M.options end if M.sections ~= nil then user_config.sections = M.sections end if M.inactive_sections ~= nil then user_config.inactive_sections = M.inactive_sections end if M.tabline ~= nil then user_config.tabline = M.tabline end if M.extensions ~= nil then user_config.extensions = M.extensions end end apply_configuration(vim.g.lualine) apply_configuration(user_config) check_single_separator() setup_theme() load_components() load_extensions() set_statusline() set_tabline() end function M.status(user_config) if vim.api.nvim_echo then vim.api.nvim_echo({ { 'lualine.nvim: status function has been ranamed to setup and will be removed by 24.03.2021, please change your configuration', 'WarningMsg' } }, true, {}) else print( 'lualine.nvim: status function has been ranamed to setup and will be removed by 24.03.2021, please change your configuration') end return M.setup(user_config) end return M