refactor: separate the child creation and initialization (#81)

- includes modified class implementation from https://github.com/rxi/classic/blob/master/classic.lua
- now base component class is created from classic.
- change to how component classes are created.
  - Don't overwrite new method to initialize a component.
    Overwrite the init method. new is responsible for
    creating class object and calling init on it.
    Unlike previous new overwrite you don't need to create
    the class (table) and return it. Instead you will recive
    the object as self and do required manipulation on that
    just like any most other oop langs. Also don't need to
    return anything from init. init's job is to initialize.
    remember to call classes init before running your operations
    unfortunately lua isn't full fledged oop lang and I don't
    how to automate this.
- changes how super classes are accesed.
  - rename Component._parent -> Component.super
  - methods on super classes now ran through super class instead
    of objects _parent self._parent as that can lead to recursive inf loop.
  See branch, diff, tabs, buffer classes call to init for example
  on pattern.
- All components updated to reflect current logic
- component loader updated to use new initialization procedure.
- updated tests
- updated BREAKING_CHANGES.md
- plus quite a bit of formatting changes in the components
  - comp.method = function(self, ...) -> function M:method(...)
BREAKING_CHANGE
This commit is contained in:
shadmansaleh 2021-09-25 23:15:42 +06:00
parent a564019d95
commit 61ac665774
24 changed files with 459 additions and 391 deletions

View File

@ -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
```

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,
}

View File

@ -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

View File

@ -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()

View File

@ -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(