diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index e512526..f9e552a 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -61,3 +61,33 @@ See [#24](https://github.com/shadmansaleh/lualine.nvim/pull/24) for details modified, removed in diff_color table option - color_error, color_warning, color_info, color_hint are now available as error, warn, info, hint in diagnostics_color table option + +### Component class refactor +***Applicable only ones responsible for custom components*** +- Now call extend method on super class to create new type of component instead of calling new with empty args. +- Don't overrite new method for initialization. Overrite init instead. +- rename Component._parent -> Component.super +- Call methods from super class directly on classes super not through + objects super or self.super +So basically if you had something like +```lua +local my_comp = require'lualine.component':new() +function mycomp:new(options, child) + local obj = self._parent:new(options, child or my_comp) + obj.x = 1 + obj.y = 2 + return obj +end +``` +change it to +```lua +local my_comp = require('lualine.component'):extend() + +function my_comp:init(options) + -- Notice carefully it's not self.super.init nor my_comp.super:init + my_comp.super.init(self, options) + self.x = 1 + self.y = 2 +end +``` + diff --git a/lua/lualine/component.lua b/lua/lualine/component.lua index 5fd2282..f660aa9 100644 --- a/lua/lualine/component.lua +++ b/lua/lualine/component.lua @@ -1,6 +1,8 @@ -- 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 @@ -27,190 +29,190 @@ for %s component. rename_notice('format', 'fmt') rename_notice('condition', 'cond') end -local Component = { - -- Creates a new component - new = function(self, options, child) - local new_component = {} - new_component.options = options - new_component._parent = child or self - setmetatable(new_component, { __index = new_component._parent }) - -- Operation that are required for creating new components but not for inheritence - if options ~= nil then - component_no = component_no + 1 - check_deprecated_options(new_component.options) - if not options.component_name then - new_component.options.component_name = tostring(component_no) - end - new_component.component_no = component_no - new_component:set_separator() - new_component:create_option_highlights() - end - return new_component - end, - set_separator = function(self) - 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 +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 + +-- Initialize new component +function M:init(options) + self.options = options or {} + component_no = component_no + 1 + check_deprecated_options(self.options) + if not 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 + +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 +end - create_option_highlights = function(self) - -- 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 - ) +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 + +-- set upper or lower case +function M:apply_case() + -- Donn't work on components that emit vim statusline escaped chars + if self.status:find '%%' and not self.status:find '%%%%' then + return + end + if self.options.upper == true then + self.status = self.status:upper() + elseif self.options.lower == true then + self.status = self.status:lower() + 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, + end + if r_padding then + self.status = self.status .. string.rep(' ', r_padding) + end +end - -- set upper or lower case - apply_case = function(self) - -- Donn't work on components that emit vim statusline escaped chars - if self.status:find '%%' and not self.status:find '%%%%' then +-- 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 +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 - if self.options.upper == true then - self.status = self.status:upper() - elseif self.options.lower == true then - self.status = self.status:lower() - end - end, + end + if separator and #separator > 0 then + self.status = self.status .. separator + self.applied_separator = self.applied_separator .. separator + end +end - -- Adds spaces to left and right of a component - apply_padding = function(self) - 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, +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 - -- Applies custom highlights for component - apply_highlights = function(self, 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 - apply_icon = function(self) - 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 - apply_separator = function(self) - 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_section_separators = function(self) - 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, - - 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)) - self.applied_separator = nil - return self.status - end, - - -- variable to store component output for manipulation - status = '', - -- Actual function that updates a component. Must be overwritten with component functionality - -- luacheck: push no unused args - update_status = function(self, is_focused) end, - -- luacheck: pop - - -- Driver code of the class - draw = function(self, default_highlight, is_focused) - self.status = '' +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 - 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_case() - self:apply_padding() - self:apply_highlights(default_highlight) - self:apply_section_separators() - self:apply_separator() - end +-- variable to store component output for manipulation +M.status = '' +-- Actual function that updates a component. Must be overwritten with component functionality +-- luacheck: push no unused args +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, -} + 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_case() + self:apply_padding() + self:apply_highlights(default_highlight) + self:apply_section_separators() + self:apply_separator() + end + return self.status +end -return Component +return M diff --git a/lua/lualine/components/branch.lua b/lua/lualine/components/branch.lua index 87832e5..637c311 100644 --- a/lua/lualine/components/branch.lua +++ b/lua/lualine/components/branch.lua @@ -1,49 +1,48 @@ -- Copyright (c) 2020-2021 shadmansaleh -- MIT license, see LICENSE for more details. -local Branch = require('lualine.component'):new() +local M = require('lualine.component'):extend() local modules = require('lualine_require').lazy_require { utils = 'lualine.utils.utils', } -- vars -Branch.git_branch = '' -Branch.git_dir = '' +M.git_branch = '' +M.git_dir = '' -- os specific path separator -Branch.sep = package.config:sub(1, 1) +M.sep = package.config:sub(1, 1) -- event watcher to watch head file -- Use file wstch for non windows and poll for windows. -- windows doesn't like file watch for some reason. -Branch.file_changed = Branch.sep ~= '\\' and vim.loop.new_fs_event() or vim.loop.new_fs_poll() -Branch.active_bufnr = '0' +M.file_changed = M.sep ~= '\\' and vim.loop.new_fs_event() or vim.loop.new_fs_poll() +M.active_bufnr = '0' local branch_cache = {} -- stores last known branch for a buffer -- Initilizer -Branch.new = function(self, options, child) - local new_branch = self._parent:new(options, child or Branch) - if not new_branch.options.icon then - new_branch.options.icon = '' -- e0a0 +M.init = function(self, options) + M.super.init(self, options) + if not self.options.icon then + self.options.icon = '' -- e0a0 end -- run watch head on load so branch is present when component is loaded - Branch.find_git_dir() + M.find_git_dir() -- update branch state of BufEnter as different Buffer may be on different repos modules.utils.define_autocmd('BufEnter', "lua require'lualine.components.branch'.find_git_dir()") - return new_branch end -Branch.update_status = function(_, is_focused) - if Branch.active_bufnr ~= vim.g.actual_curbuf then +M.update_status = function(_, is_focused) + if M.active_bufnr ~= vim.g.actual_curbuf then -- Workaround for https://github.com/hoob3rt/lualine.nvim/issues/286 -- See upstream issue https://github.com/neovim/neovim/issues/15300 -- Diff is out of sync re sync it. - Branch.find_git_dir() + M.find_git_dir() end if not is_focused then return branch_cache[vim.fn.bufnr()] or '' end - return Branch.git_branch + return M.git_branch end local git_dir_cache = {} -- Stores git paths that we already know of -- returns full path to git directory for current directory -function Branch.find_git_dir() +function M.find_git_dir() -- get file dir so we can search from that dir local file_dir = vim.fn.expand '%:p:h' local root_dir = file_dir @@ -54,7 +53,7 @@ function Branch.find_git_dir() git_dir = git_dir_cache[root_dir] break end - local git_path = root_dir .. Branch.sep .. '.git' + local git_path = root_dir .. M.sep .. '.git' local git_file_stat = vim.loop.fs_stat(git_path) if git_file_stat then if git_file_stat.type == 'directory' then @@ -66,12 +65,12 @@ function Branch.find_git_dir() git_dir = git_dir:match 'gitdir: (.+)$' file:close() -- submodule / relative file path - if git_dir and git_dir:sub(1, 1) ~= Branch.sep and not git_dir:match '^%a:.*$' then + if git_dir and git_dir:sub(1, 1) ~= M.sep and not git_dir:match '^%a:.*$' then git_dir = git_path:match '(.*).git' .. git_dir end end if git_dir then - local head_file_stat = vim.loop.fs_stat(git_dir .. Branch.sep .. 'HEAD') + local head_file_stat = vim.loop.fs_stat(git_dir .. M.sep .. 'HEAD') if head_file_stat and head_file_stat.type == 'file' then break else @@ -79,54 +78,54 @@ function Branch.find_git_dir() end end end - root_dir = root_dir:match('(.*)' .. Branch.sep .. '.-') + root_dir = root_dir:match('(.*)' .. M.sep .. '.-') end git_dir_cache[file_dir] = git_dir - if Branch.git_dir ~= git_dir then - Branch.git_dir = git_dir - Branch.update_branch() + if M.git_dir ~= git_dir then + M.git_dir = git_dir + M.update_branch() end return git_dir end -- sets git_branch veriable to branch name or commit hash if not on branch -function Branch.get_git_head(head_file) +function M.get_git_head(head_file) local f_head = io.open(head_file) if f_head then local HEAD = f_head:read() f_head:close() local branch = HEAD:match 'ref: refs/heads/(.+)$' if branch then - Branch.git_branch = branch + M.git_branch = branch else - Branch.git_branch = HEAD:sub(1, 6) + M.git_branch = HEAD:sub(1, 6) end end return nil end -- Update branch -function Branch.update_branch() - Branch.active_bufnr = tostring(vim.fn.bufnr()) - Branch.file_changed:stop() - local git_dir = Branch.git_dir +function M.update_branch() + M.active_bufnr = tostring(vim.fn.bufnr()) + M.file_changed:stop() + local git_dir = M.git_dir if git_dir and #git_dir > 0 then - local head_file = git_dir .. Branch.sep .. 'HEAD' - Branch.get_git_head(head_file) - Branch.file_changed:start( + local head_file = git_dir .. M.sep .. 'HEAD' + M.get_git_head(head_file) + M.file_changed:start( head_file, - Branch.sep ~= '\\' and {} or 1000, + M.sep ~= '\\' and {} or 1000, vim.schedule_wrap(function() -- reset file-watch - Branch.update_branch() + M.update_branch() end) ) else -- set to '' when git dir was not found - Branch.git_branch = '' + M.git_branch = '' end - branch_cache[vim.fn.bufnr()] = Branch.git_branch + branch_cache[vim.fn.bufnr()] = M.git_branch end -return Branch +return M diff --git a/lua/lualine/components/buffers.lua b/lua/lualine/components/buffers.lua index 4bafc41..86ec797 100644 --- a/lua/lualine/components/buffers.lua +++ b/lua/lualine/components/buffers.lua @@ -1,6 +1,6 @@ -- Copyright (c) 2020-2021 shadmansaleh -- MIT license, see LICENSE for more details. -local Buffers = require('lualine.component'):new() +local M = require('lualine.component'):extend() local highlight = require 'lualine.highlight' local default_options = { @@ -134,29 +134,28 @@ function Buffer:name() or vim.fn.pathshorten(vim.fn.fnamemodify(self.file, ':p:.')) end -function Buffers:new(options, child) - local newObj = self._parent:new(options, child or Buffers) +function M:init(options) + M.super.init(self, options) default_options.buffers_color = { active = get_hl(options.self.section, true), inactive = get_hl(options.self.section, false), } - newObj.options = vim.tbl_deep_extend('keep', newObj.options or {}, default_options) - newObj.highlights = { + self.options = vim.tbl_deep_extend('keep', self.options or {}, default_options) + self.highlights = { active = highlight.create_component_highlight_group( - newObj.options.buffers_color.active, + self.options.buffers_color.active, 'buffers_active', - newObj.options + self.options ), inactive = highlight.create_component_highlight_group( - newObj.options.buffers_color.inactive, + self.options.buffers_color.inactive, 'buffers_active', - newObj.options + self.options ), } - return newObj end -function Buffers:update_status() +function M:update_status() local data = {} local buffers = {} for b = 1, vim.fn.bufnr '$' do @@ -267,4 +266,4 @@ vim.cmd [[ endfunction ]] -return Buffers +return M diff --git a/lua/lualine/components/diagnostics.lua b/lua/lualine/components/diagnostics.lua index a8f915b..7eb024d 100644 --- a/lua/lualine/components/diagnostics.lua +++ b/lua/lualine/components/diagnostics.lua @@ -7,7 +7,7 @@ local modules = lualine_require.lazy_require { utils_notices = 'lualine.utils.notices', } -local Diagnostics = lualine_require.require('lualine.component'):new() +local M = lualine_require.require 'lualine.component':extend() local function check_deprecated_options(options) if options.color_error or options.color_warn or options.color_info or options.color_hint then @@ -83,56 +83,55 @@ local default_options = { }, } -- Initializer -Diagnostics.new = function(self, options, child) +function M:init(options) -- Run super() - local new_diagnostics = self._parent:new(options, child or Diagnostics) + M.super.init(self, options) -- Apply default options - new_diagnostics.options = vim.tbl_deep_extend('keep', new_diagnostics.options or {}, default_options) - check_deprecated_options(new_diagnostics.options) + self.options = vim.tbl_deep_extend('keep', self.options or {}, default_options) + check_deprecated_options(self.options) -- Apply default symbols - new_diagnostics.symbols = vim.tbl_extend( + self.symbols = vim.tbl_extend( 'keep', - new_diagnostics.options.symbols or {}, - new_diagnostics.options.icons_enabled ~= false and default_symbols.icons or default_symbols.no_icons + self.options.symbols or {}, + self.options.icons_enabled ~= false and default_symbols.icons or default_symbols.no_icons ) -- Initialize highlight groups - if new_diagnostics.options.colored then - new_diagnostics.highlight_groups = { + if self.options.colored then + self.highlight_groups = { error = modules.highlight.create_component_highlight_group( - new_diagnostics.options.diagnostics_color.error, + self.options.diagnostics_color.error, 'diagnostics_error', - new_diagnostics.options + self.options ), warn = modules.highlight.create_component_highlight_group( - new_diagnostics.options.diagnostics_color.warn, + self.options.diagnostics_color.warn, 'diagnostics_warn', - new_diagnostics.options + self.options ), info = modules.highlight.create_component_highlight_group( - new_diagnostics.options.diagnostics_color.info, + self.options.diagnostics_color.info, 'diagnostics_info', - new_diagnostics.options + self.options ), hint = modules.highlight.create_component_highlight_group( - new_diagnostics.options.diagnostics_color.hint, + self.options.diagnostics_color.hint, 'diagnostics_hint', - new_diagnostics.options + self.options ), } end -- Error out no source - if #new_diagnostics.options.sources < 1 then + if #self.options.sources < 1 then print 'no sources for diagnostics configured' return '' end -- Initialize variable to store last update so we can use it in insert -- mode for no update_in_insert - new_diagnostics.last_update = '' - return new_diagnostics + self.last_update = '' end -Diagnostics.update_status = function(self) +function M:update_status() if not self.options.update_in_insert and vim.api.nvim_get_mode().mode:sub(1, 1) == 'i' then return self.last_update end @@ -175,7 +174,7 @@ Diagnostics.update_status = function(self) return self.last_update end -Diagnostics.diagnostic_sources = { +M.diagnostic_sources = { nvim_lsp = function() local error_count = vim.lsp.diagnostic.get_count(0, 'Error') local warning_count = vim.lsp.diagnostic.get_count(0, 'Warning') @@ -220,11 +219,11 @@ Diagnostics.diagnostic_sources = { end, } -Diagnostics.get_diagnostics = function(sources) +M.get_diagnostics = function(sources) local result = {} for index, source in ipairs(sources) do if type(source) == 'string' then - local error_count, warning_count, info_count, hint_count = Diagnostics.diagnostic_sources[source]() + local error_count, warning_count, info_count, hint_count = M.diagnostic_sources[source]() result[index] = { error = error_count, warn = warning_count, @@ -245,4 +244,4 @@ Diagnostics.get_diagnostics = function(sources) return result end -return Diagnostics +return M diff --git a/lua/lualine/components/diff.lua b/lua/lualine/components/diff.lua index f0fd098..b77c972 100644 --- a/lua/lualine/components/diff.lua +++ b/lua/lualine/components/diff.lua @@ -7,7 +7,7 @@ local modules = lualine_require.lazy_require { highlight = 'lualine.highlight', Job = 'lualine.utils.job', } -local Diff = lualine_require.require('lualine.component'):new() +local M = lualine_require.require('lualine.component'):extend() local function check_deprecated_options(options) if options.color_added or options.color_modified or options.color_removed then @@ -35,12 +35,12 @@ end -- Vars -- variable to store git diff stats -Diff.git_diff = nil +M.git_diff = nil -- accumulates output from diff process -Diff.diff_output_cache = {} +M.diff_output_cache = {} -- variable to store git_diff job -Diff.diff_job = nil -Diff.active_bufnr = '0' +M.diff_job = nil +M.active_bufnr = '0' local diff_cache = {} -- Stores last known value of diff of a buffer @@ -61,54 +61,52 @@ local default_options = { } -- Initializer -Diff.new = function(self, options, child) - local new_instance = self._parent:new(options, child or Diff) - new_instance.options = vim.tbl_deep_extend('keep', new_instance.options or {}, default_options) - check_deprecated_options(new_instance.options) +function M:init(options) + M.super.init(self, options) + self.options = vim.tbl_deep_extend('keep', self.options or {}, default_options) + check_deprecated_options(self.options) -- create highlights and save highlight_name in highlights table - if new_instance.options.colored then - new_instance.highlights = { + if self.options.colored then + self.highlights = { added = modules.highlight.create_component_highlight_group( - new_instance.options.diff_color.added, + self.options.diff_color.added, 'diff_added', - new_instance.options + self.options ), modified = modules.highlight.create_component_highlight_group( - new_instance.options.diff_color.modified, + self.options.diff_color.modified, 'diff_modified', - new_instance.options + self.options ), removed = modules.highlight.create_component_highlight_group( - new_instance.options.diff_color.removed, + self.options.diff_color.removed, 'diff_removed', - new_instance.options + self.options ), } end - Diff.diff_checker_enabled = type(new_instance.options.source) ~= 'function' + M.diff_checker_enabled = type(self.options.source) ~= 'function' - if Diff.diff_checker_enabled then + if M.diff_checker_enabled then -- setup internal source modules.utils.define_autocmd('BufEnter', "lua require'lualine.components.diff'.update_diff_args()") modules.utils.define_autocmd('BufWritePost', "lua require'lualine.components.diff'.update_git_diff()") - Diff.update_diff_args() + M.update_diff_args() end - - return new_instance end -- Function that runs everytime statusline is updated -Diff.update_status = function(self, is_focused) +function M:update_status(is_focused) local git_diff - if Diff.diff_checker_enabled then - if Diff.active_bufnr ~= vim.g.actual_curbuf then + if M.diff_checker_enabled then + if M.active_bufnr ~= vim.g.actual_curbuf then -- Workaround for https://github.com/hoob3rt/lualine.nvim/issues/286 -- See upstream issue https://github.com/neovim/neovim/issues/15300 -- Diff is out of sync re sync it. - Diff.update_diff_args() + M.update_diff_args() end - git_diff = Diff.git_diff + git_diff = M.git_diff else git_diff = self.options.source() end @@ -154,15 +152,15 @@ end -- removed = removed_count, -- } -- error_code = { added = -1, modified = -1, removed = -1 } -function Diff.get_sign_count() - if Diff.diff_checker_enabled then - Diff.update_diff_args() +function M.get_sign_count() + if M.diff_checker_enabled then + M.update_diff_args() end - return Diff.git_diff or { added = -1, modified = -1, removed = -1 } + return M.git_diff or { added = -1, modified = -1, removed = -1 } end -- process diff data and update git_diff{ added, removed, modified } -function Diff.process_diff(data) +function M.process_diff(data) -- Adapted from https://github.com/wbthomason/nvim-vcs.lua local added, removed, modified = 0, 0, 0 for _, line in ipairs(data) do @@ -185,19 +183,19 @@ function Diff.process_diff(data) end end end - Diff.git_diff = { added = added, modified = modified, removed = removed } + M.git_diff = { added = added, modified = modified, removed = removed } end -- Updates the job args -function Diff.update_diff_args() +function M.update_diff_args() -- Donn't show git diff when current buffer doesn't have a filename - Diff.active_bufnr = tostring(vim.fn.bufnr()) + M.active_bufnr = tostring(vim.fn.bufnr()) if #vim.fn.expand '%' == 0 then - Diff.diff_args = nil - Diff.git_diff = nil + M.diff_args = nil + M.git_diff = nil return end - Diff.diff_args = { + M.diff_args = { cmd = string.format( [[git -C %s --no-pager diff --no-color --no-ext-diff -U0 -- %s]], vim.fn.expand '%:h', @@ -205,40 +203,40 @@ function Diff.update_diff_args() ), on_stdout = function(_, data) if next(data) then - Diff.diff_output_cache = vim.list_extend(Diff.diff_output_cache, data) + M.diff_output_cache = vim.list_extend(M.diff_output_cache, data) end end, on_stderr = function(_, data) data = table.concat(data, '\n') if #data > 1 or (#data == 1 and #data[1] > 0) then - Diff.git_diff = nil - Diff.diff_output_cache = {} + M.git_diff = nil + M.diff_output_cache = {} end end, on_exit = function() - if #Diff.diff_output_cache > 0 then - Diff.process_diff(Diff.diff_output_cache) + if #M.diff_output_cache > 0 then + M.process_diff(M.diff_output_cache) else - Diff.git_diff = { added = 0, modified = 0, removed = 0 } + M.git_diff = { added = 0, modified = 0, removed = 0 } end - diff_cache[vim.fn.bufnr()] = Diff.git_diff + diff_cache[vim.fn.bufnr()] = M.git_diff end, } - Diff.update_git_diff() + M.update_git_diff() end -- Update git_diff veriable -function Diff.update_git_diff() - if Diff.diff_args then - Diff.diff_output_cache = {} - if Diff.diff_job then - Diff.diff_job:stop() +function M.update_git_diff() + if M.diff_args then + M.diff_output_cache = {} + if M.diff_job then + M.diff_job:stop() end - Diff.diff_job = modules.Job(Diff.diff_args) - if Diff.diff_job then - Diff.diff_job:start() + M.diff_job = modules.Job(M.diff_args) + if M.diff_job then + M.diff_job:start() end end end -return Diff +return M diff --git a/lua/lualine/components/encoding.lua b/lua/lualine/components/encoding.lua index a2f5fdd..d191395 100644 --- a/lua/lualine/components/encoding.lua +++ b/lua/lualine/components/encoding.lua @@ -1,9 +1,9 @@ -- Copyright (c) 2020-2021 hoob3rt -- MIT license, see LICENSE for more details. -local Encoding = require('lualine.component'):new() +local M = require('lualine.component'):extend() -Encoding.update_status = function() +M.update_status = function() return [[%{strlen(&fenc)?&fenc:&enc}]] end -return Encoding +return M diff --git a/lua/lualine/components/fileformat.lua b/lua/lualine/components/fileformat.lua index a36d7ef..8ca764a 100644 --- a/lua/lualine/components/fileformat.lua +++ b/lua/lualine/components/fileformat.lua @@ -1,20 +1,20 @@ -- Copyright (c) 2020-2021 shadmansaleh -- MIT license, see LICENSE for more details. -local FileFormat = require('lualine.component'):new() +local M = require('lualine.component'):extend() -- stylua: ignore -FileFormat.icon = { +M.icon = { unix = '', -- e712 dos = '', -- e70f mac = '' -- e711 } -FileFormat.update_status = function(self) +M.update_status = function(self) if self.options.icons_enabled and not self.options.icon then local format = vim.bo.fileformat - return FileFormat.icon[format] or format + return M.icon[format] or format end return vim.bo.fileformat end -return FileFormat +return M diff --git a/lua/lualine/components/filename.lua b/lua/lualine/components/filename.lua index 2f4f6f3..27346d2 100644 --- a/lua/lualine/components/filename.lua +++ b/lua/lualine/components/filename.lua @@ -1,6 +1,6 @@ -- Copyright (c) 2020-2021 shadmansaleh -- MIT license, see LICENSE for more details. -local FileName = require('lualine.component'):new() +local M = require('lualine.component'):extend() local default_options = { symbols = { modified = '[+]', readonly = '[-]' }, @@ -18,13 +18,12 @@ local function shorten_path(path, sep) return path:gsub(string.format('([^%s])[^%s]+%%%s', sep, sep, sep), '%1' .. sep, 1) end -FileName.new = function(self, options, child) - local new_instance = self._parent:new(options, child or FileName) - new_instance.options = vim.tbl_deep_extend('keep', new_instance.options or {}, default_options) - return new_instance +M.init = function(self, options) + M.super.init(self, options) + self.options = vim.tbl_deep_extend('keep', self.options or {}, default_options) end -FileName.update_status = function(self) +M.update_status = function(self) local data if self.options.path == 1 then -- relative path @@ -63,4 +62,4 @@ FileName.update_status = function(self) return data end -return FileName +return M diff --git a/lua/lualine/components/filesize.lua b/lua/lualine/components/filesize.lua index 523dda2..4336d21 100644 --- a/lua/lualine/components/filesize.lua +++ b/lua/lualine/components/filesize.lua @@ -1,6 +1,6 @@ -- Copyright (c) 2020-2021 shadmansaleh -- MIT license, see LICENSE for more details. -local M = require('lualine.component'):new() +local M = require('lualine.component'):extend() M.update_status = function() local file = vim.fn.expand '%:p' diff --git a/lua/lualine/components/filetype.lua b/lua/lualine/components/filetype.lua index fac7c57..2c26a03 100644 --- a/lua/lualine/components/filetype.lua +++ b/lua/lualine/components/filetype.lua @@ -5,7 +5,7 @@ local modules = lualine_require.lazy_require { highlight = 'lualine.highlight', utils = 'lualine.utils.utils', } -local FileType = lualine_require.require('lualine.component'):new() +local M = lualine_require.require('lualine.component'):extend() local function check_deprecated_options(options) local function rename_notice(before, now) @@ -33,18 +33,17 @@ local default_options = { icon_only = false, } -function FileType:new(options, child) - local new_instance = self._parent:new(options, child or FileType) - new_instance.options = vim.tbl_deep_extend('keep', new_instance.options or {}, default_options) - check_deprecated_options(new_instance.options) - return new_instance +function M:init(options) + M.super.init(self, options) + self.options = vim.tbl_deep_extend('keep', self.options or {}, default_options) + check_deprecated_options(self.options) end -function FileType.update_status() +function M.update_status() return vim.bo.filetype or '' end -function FileType:apply_icon() +function M:apply_icon() if not self.options.icons_enabled then return end @@ -87,4 +86,4 @@ function FileType:apply_icon() end end -return FileType +return M diff --git a/lua/lualine/components/hostname.lua b/lua/lualine/components/hostname.lua index 5ac4112..4b04d3a 100644 --- a/lua/lualine/components/hostname.lua +++ b/lua/lualine/components/hostname.lua @@ -1,7 +1,7 @@ -- Copyright (c) 2020-2021 hoob3rt -- MIT license, see LICENSE for more details. -local HostName = require('lualine.component'):new() +local M = require('lualine.component'):extend() -HostName.update_status = vim.loop.os_gethostname +M.update_status = vim.loop.os_gethostname -return HostName +return M diff --git a/lua/lualine/components/location.lua b/lua/lualine/components/location.lua index 39b2eae..91aaac5 100644 --- a/lua/lualine/components/location.lua +++ b/lua/lualine/components/location.lua @@ -1,9 +1,9 @@ -- Copyright (c) 2020-2021 hoob3rt -- MIT license, see LICENSE for more details. -local Location = require('lualine.component'):new() +local M = require('lualine.component'):extend() -Location.update_status = function() +M.update_status = function() return [[%3l:%-2c]] end -return Location +return M diff --git a/lua/lualine/components/mode.lua b/lua/lualine/components/mode.lua index cec8222..092a674 100644 --- a/lua/lualine/components/mode.lua +++ b/lua/lualine/components/mode.lua @@ -1,9 +1,10 @@ -- Copyright (c) 2020-2021 hoob3rt -- MIT license, see LICENSE for more details. local require = require('lualine_require').require -local Mode = require('lualine.component'):new() local get_mode = require('lualine.utils.mode').get_mode -Mode.update_status = get_mode +local M = require('lualine.component'):extend() -return Mode +M.update_status = get_mode + +return M diff --git a/lua/lualine/components/progress.lua b/lua/lualine/components/progress.lua index ac7e52f..0b6aec8 100644 --- a/lua/lualine/components/progress.lua +++ b/lua/lualine/components/progress.lua @@ -1,9 +1,9 @@ -- Copyright (c) 2020-2021 hoob3rt -- MIT license, see LICENSE for more details. -local Progress = require('lualine.component'):new() +local M = require('lualine.component'):extend() -Progress.update_status = function() +M.update_status = function() return [[%3P]] end -return Progress +return M diff --git a/lua/lualine/components/special/eval_func_component.lua b/lua/lualine/components/special/eval_func_component.lua index 4656b89..a209eba 100644 --- a/lua/lualine/components/special/eval_func_component.lua +++ b/lua/lualine/components/special/eval_func_component.lua @@ -1,36 +1,35 @@ -- Copyright (c) 2020-2021 shadmansaleh -- MIT license, see LICENSE for more details. +local M = require('lualine.component'):extend() -local EvalFuncComponent = require('lualine.component'):new() - -EvalFuncComponent.update_status = function(self) +function M:update_status() local component = self.options[1] local ok, status if self.options.type == nil then - ok, status = pcall(EvalFuncComponent.lua_eval, component) + ok, status = pcall(M.lua_eval, component) if not ok then - status = EvalFuncComponent.vim_function(component) + status = M.vim_function(component) end else if self.options.type == 'luae' then - ok, status = pcall(EvalFuncComponent.lua_eval, component) + ok, status = pcall(M.lua_eval, component) if not ok then status = nil end elseif self.options.type == 'vimf' then - status = EvalFuncComponent.vim_function(component) + status = M.vim_function(component) end end return status end -EvalFuncComponent.lua_eval = function(code) +function M.lua_eval(code) local result = loadstring('return ' .. code)() assert(result, 'String expected got nil') return tostring(result) end -EvalFuncComponent.vim_function = function(name) +function M.vim_function(name) -- vim function component local ok, return_val = pcall(vim.api.nvim_call_function, name, {}) if not ok then @@ -40,4 +39,4 @@ EvalFuncComponent.vim_function = function(name) return ok and return_val or '' end -return EvalFuncComponent +return M diff --git a/lua/lualine/components/special/function_component.lua b/lua/lualine/components/special/function_component.lua index b360c31..4856dad 100644 --- a/lua/lualine/components/special/function_component.lua +++ b/lua/lualine/components/special/function_component.lua @@ -1,8 +1,8 @@ -- Copyright (c) 2020-2021 shadmansaleh -- MIT license, see LICENSE for more details. -local FunctionComponent = require('lualine.component'):new() +local M = require('lualine.component'):extend() -FunctionComponent.update_status = function(self, is_focused) +M.update_status = function(self, is_focused) -- 1st element in options table is the function provided by config local ok, retval ok, retval = pcall(self.options[1], self, is_focused) @@ -18,4 +18,4 @@ FunctionComponent.update_status = function(self, is_focused) return retval end -return FunctionComponent +return M diff --git a/lua/lualine/components/special/vim_var_component.lua b/lua/lualine/components/special/vim_var_component.lua index eb46b28..f6853a2 100644 --- a/lua/lualine/components/special/vim_var_component.lua +++ b/lua/lualine/components/special/vim_var_component.lua @@ -1,7 +1,8 @@ -- Copyright (c) 2020-2021 shadmansaleh -- MIT license, see LICENSE for more details. -local VarComponent = require('lualine.component'):new() -VarComponent.update_status = function(self) +local M = require('lualine.component'):extend() + +function M:update_status() local component = self.options[1] -- vim veriable component -- accepts g:, v:, t:, w:, b:, o, go:, vo:, to:, wo:, bo: @@ -31,4 +32,4 @@ VarComponent.update_status = function(self) return ok and return_val or '' end -return VarComponent +return M diff --git a/lua/lualine/components/tabs.lua b/lua/lualine/components/tabs.lua index c55b72e..57e5495 100644 --- a/lua/lualine/components/tabs.lua +++ b/lua/lualine/components/tabs.lua @@ -1,6 +1,6 @@ -- Copyright (c) 2020-2021 shadmansaleh -- MIT license, see LICENSE for more details. -local Tabs = require('lualine.component'):new() +local M = require('lualine.component'):extend() local highlight = require 'lualine.highlight' local default_options = { @@ -103,30 +103,29 @@ function Tab:separator_after() end end -function Tabs:new(options, child) - local newObj = self._parent:new(options, child or Tabs) +function M:init(options) + M.super.init(self, options) default_options.tabs_color = { active = get_hl(options.self.section, true), inactive = get_hl(options.self.section, false), } - newObj.options = vim.tbl_deep_extend('keep', newObj.options or {}, default_options) + self.options = vim.tbl_deep_extend('keep', self.options or {}, default_options) -- stylua: ignore - newObj.highlights = { + self.highlights = { active = highlight.create_component_highlight_group( - newObj.options.tabs_color.active, + self.options.tabs_color.active, 'tabs_active', - newObj.options + self.options ), inactive = highlight.create_component_highlight_group( - newObj.options.tabs_color.inactive, + self.options.tabs_color.inactive, 'tabs_active', - newObj.options + self.options ), } - return newObj end -function Tabs:update_status() +function M:update_status() local data = {} local tabs = {} for t = 1, vim.fn.tabpagenr '$' do @@ -214,4 +213,4 @@ vim.cmd [[ endfunction ]] -return Tabs +return M diff --git a/lua/lualine/utils/class.lua b/lua/lualine/utils/class.lua new file mode 100644 index 0000000..83700fc --- /dev/null +++ b/lua/lualine/utils/class.lua @@ -0,0 +1,43 @@ +-- Adapted from https://github.com/rxi/classic/blob/master/classic.lua +local Object = {} + +Object.__index = Object + +-- luacheck: push no unused args +-- Initializer +function Object:init(...) end +-- luacheck: pop + +-- Extened base class to create a child class +function Object:extend() + local cls = {} + for k, v in pairs(self) do + if k:find '__' == 1 then + cls[k] = v + end + end + cls.__index = cls + cls.super = self + setmetatable(cls, self) + return cls +end + +-- luacheck: push no unused args +function Object:__tostring() + return 'Object' +end +-- luacheck: pop + +-- Creates a new object +function Object:new(...) + local obj = setmetatable({}, self) + obj:init(...) + return obj +end + +-- Creates a new object +function Object:__call(...) + return self:new(...) +end + +return Object diff --git a/lua/lualine/utils/loader.lua b/lua/lualine/utils/loader.lua index d8e5547..0e05682 100644 --- a/lua/lualine/utils/loader.lua +++ b/lua/lualine/utils/loader.lua @@ -12,13 +12,13 @@ local sep = lualine_require.sep local component_types = { luaf = function(component) - return require('lualine.components.special.function_component'):new(component) + return require 'lualine.components.special.function_component'(component) end, mod = function(component) local ok, loaded_component = pcall(require, 'lualine.components.' .. component[1]) if ok then component.component_name = component[1] - loaded_component = loaded_component:new(component) + loaded_component = loaded_component(component) return loaded_component end end, @@ -27,13 +27,13 @@ local component_types = { component[1] = function() return stl_expr end - return require('lualine.components.special.function_component'):new(component) + return require 'lualine.components.special.function_component'(component) end, var = function(component) - return require('lualine.components.special.vim_var_component'):new(component) + return require 'lualine.components.special.vim_var_component'(component) end, ['_'] = function(component) - return require('lualine.components.special.eval_func_component'):new(component) + return require 'lualine.components.special.eval_func_component'(component) end, } diff --git a/lua/tests/helpers.lua b/lua/tests/helpers.lua index 1f46144..6a3516e 100644 --- a/lua/tests/helpers.lua +++ b/lua/tests/helpers.lua @@ -17,7 +17,7 @@ M.assert_component = function(component, opts, result) if component == nil then component = 'special.function_component' end - local comp = require('lualine.components.' .. component):new(opts) + local comp = require('lualine.components.' .. component)(opts) eq(result, comp:draw(opts.hl)) end diff --git a/lua/tests/spec/component_spec.lua b/lua/tests/spec/component_spec.lua index 5e02586..3e0f74a 100644 --- a/lua/tests/spec/component_spec.lua +++ b/lua/tests/spec/component_spec.lua @@ -12,20 +12,20 @@ local stub = require 'luassert.stub' describe('Component:', function() it('can select separators', function() local opts = build_component_opts() - local comp = require('lualine.components.special.function_component'):new(opts) + local comp = require 'lualine.components.special.function_component'(opts) -- correct for lualine_c eq('', comp.options.separator) local opts2 = build_component_opts { self = { section = 'lualine_y' } } - local comp2 = require('lualine.components.special.function_component'):new(opts2) + local comp2 = require 'lualine.components.special.function_component'(opts2) -- correct for lualine_u eq('', comp2.options.separator) end) it('can provide unique identifier', function() local opts1 = build_component_opts() - local comp1 = require('lualine.components.special.function_component'):new(opts1) + local comp1 = require 'lualine.components.special.function_component'(opts1) local opts2 = build_component_opts() - local comp2 = require('lualine.components.special.function_component'):new(opts2) + local comp2 = require 'lualine.components.special.function_component'(opts2) neq(comp1.component_no, comp2.component_no) end) @@ -35,7 +35,7 @@ describe('Component:', function() local hl = require 'lualine.highlight' stub(hl, 'create_component_highlight_group') hl.create_component_highlight_group.returns 'MyCompHl' - local comp1 = require('lualine.components.special.function_component'):new(opts1) + local comp1 = require 'lualine.components.special.function_component'(opts1) eq('MyCompHl', comp1.options.color_highlight) -- color highlight wan't in options when create_comp_hl was -- called so remove it before assert @@ -46,7 +46,7 @@ describe('Component:', function() local opts2 = build_component_opts { color = color } stub(hl, 'create_component_highlight_group') hl.create_component_highlight_group.returns 'MyCompLinkedHl' - local comp2 = require('lualine.components.special.function_component'):new(opts2) + local comp2 = require 'lualine.components.special.function_component'(opts2) eq('MyCompLinkedHl', comp2.options.color_highlight) -- color highlight wan't in options when create_comp_hl was -- called so remove it before assert @@ -206,7 +206,7 @@ describe('Component:', function() padding = 0, color = 'MyHl', } - local comp = require('lualine.components.special.function_component'):new(opts) + local comp = require 'lualine.components.special.function_component'(opts) local custom_link_hl_name = 'lualine_' .. comp.options.component_name .. '_no_mode' eq('%#' .. custom_link_hl_name .. '#test', comp:draw(opts.hl)) local opts2 = build_component_opts { @@ -217,7 +217,7 @@ describe('Component:', function() local hl = require 'lualine.highlight' stub(hl, 'component_format_highlight') hl.component_format_highlight.returns '%#MyCompHl#' - local comp2 = require('lualine.components.special.function_component'):new(opts2) + local comp2 = require 'lualine.components.special.function_component'(opts2) assert_component(nil, opts2, '%#MyCompHl#test') assert.stub(hl.component_format_highlight).was_called_with(comp2.options.color_highlight) hl.component_format_highlight:revert() diff --git a/lua/tests/spec/utils_spec.lua b/lua/tests/spec/utils_spec.lua index ced2a16..5f4e9ef 100644 --- a/lua/tests/spec/utils_spec.lua +++ b/lua/tests/spec/utils_spec.lua @@ -59,8 +59,8 @@ describe('Section genarator', function() it('can draw', function() local opts = build_component_opts { section_separators = { left = '', right = '' } } local section = { - require('lualine.components.special.function_component'):new(opts), - require('lualine.components.special.function_component'):new(opts), + require 'lualine.components.special.function_component'(opts), + require 'lualine.components.special.function_component'(opts), } eq('%#lualine_MySection_normal# test %#lualine_MySection_normal# test ', sec.draw_section(section, 'MySection')) end) @@ -78,9 +78,9 @@ describe('Section genarator', function() } require('lualine.highlight').create_highlight_groups(require 'lualine.themes.gruvbox') local section = { - require('lualine.components.special.function_component'):new(opts), - require('lualine.components.special.function_component'):new(opts_colored), - require('lualine.components.special.function_component'):new(opts), + require 'lualine.components.special.function_component'(opts), + require 'lualine.components.special.function_component'(opts_colored), + require 'lualine.components.special.function_component'(opts), } local highlight_name2 = 'lualine_' .. section[2].options.component_name .. '_no_mode' -- Removes separator on string color @@ -88,14 +88,14 @@ describe('Section genarator', function() '%#lualine_MySection_normal# test %#' .. highlight_name2 .. '#' .. ' test %#lualine_MySection_normal# test ', sec.draw_section(section, 'MySection') ) - section[2] = require('lua.lualine.components.special.function_component'):new(opts_colored2) + section[2] = require 'lua.lualine.components.special.function_component'(opts_colored2) local highlight_name = '%#lualine_c_' .. section[2].options.component_name .. '_normal#' -- Removes separator on color with bg eq( '%#lualine_MySection_normal# test ' .. highlight_name .. ' test %#lualine_MySection_normal# test ', sec.draw_section(section, 'MySection') ) - section[2] = require('lua.lualine.components.special.function_component'):new(opts_colored3) + section[2] = require 'lua.lualine.components.special.function_component'(opts_colored3) highlight_name2 = '%#lualine_c_' .. section[2].options.component_name .. '_normal#' -- Doesn't remove separator on color without bg eq(