[Breaking] Refactor: switch to %{%expr%} from %!expr

Huge change to internal mechanics.
- Now %{%expr%} blocks are used for evaluating statusline instead of
  %!expr . Pros for this is statusline is evaluated on current win and
  buf context instead of active win & bufs context.
- Now all components branch & diff(These two are cached) including users
  function components updates on inactive status.
  - now components update status and function components receive an
    argument (is_focused) when called. It indicates whether it's running
    for active or inactive statusline.
- Now lualine no longer aggrasively takes over 'statusline' option.
  instead it sets the global version of statusline option. So it's
  possible to unset it to hide lualine . Or set buffer local version
  of that option to have different statusline then lualine on thay
  buffer
- Switch vim.o to vim.go or vim.opt.
- BugFix autcommands being set everytime an instence of diff or branch
  component is created
- Added new utils functions define_autocmd & is_focused
- Remove utils function lualine_eval
- Removed hacky require cache modification from component.lua
This commit is contained in:
shadmansaleh 2021-08-08 22:03:58 +06:00
parent cb5c4c031e
commit fac96d71cc
12 changed files with 58 additions and 67 deletions

View File

@ -5,14 +5,6 @@ local highlight = require 'lualine.highlight'
-- Used to provide a unique id for each component -- Used to provide a unique id for each component
local component_no = 1 local component_no = 1
-- Here we're manupulation the require() cache so when we
-- require('lualine.component.components') it will return this table
-- It's hacky but package.loaded is documented in lua docs so from
-- standereds point of view we're good ]. I think it's better than
-- modifiying global state
package.loaded['lualine.component.components'] = {}
local components = package.loaded['lualine.component.components']
local Component = { local Component = {
-- Creates a new component -- Creates a new component
new = function(self, options, child) new = function(self, options, child)
@ -27,7 +19,6 @@ local Component = {
new_component.options.component_name = tostring(component_no) new_component.options.component_name = tostring(component_no)
end end
new_component.component_no = component_no new_component.component_no = component_no
components[component_no] = new_component
new_component:set_separator() new_component:set_separator()
new_component:create_option_highlights() new_component:create_option_highlights()
end end
@ -157,22 +148,13 @@ local Component = {
-- luacheck: pop -- luacheck: pop
-- Driver code of the class -- Driver code of the class
draw = function(self, default_highlight, statusline_inactive) draw = function(self, default_highlight, is_focused)
-- Check if we are in in inactive state and need to enable inactive_eval
-- for this compoennt
if self.inactive_eval and not statusline_inactive and vim.g.statusline_winid ~=
vim.fn.win_getid() then
-- In that case we'll return a evaluator
self.status = '%' .. string.format(
'{%%v:lua.require\'lualine.utils.utils\'.lualine_eval(%s,\'\',v:true)%%}',
tostring(self.component_no))
return self.status
end
self.status = '' self.status = ''
if self.options.condition ~= nil and self.options.condition() ~= true then if self.options.condition ~= nil and self.options.condition() ~= true then
return self.status return self.status
end end
local status = self:update_status() local status = self:update_status(is_focused)
if self.options.format then status = self.options.format(status or '') end if self.options.format then status = self.options.format(status or '') end
if type(status) == 'string' and #status > 0 then if type(status) == 'string' and #status > 0 then
self.status = status self.status = status
@ -181,10 +163,8 @@ local Component = {
self:apply_padding() self:apply_padding()
self:apply_section_separators() self:apply_section_separators()
self:apply_highlights(default_highlight) self:apply_highlights(default_highlight)
if not (statusline_inactive and self.last_component) then
self:apply_separator() self:apply_separator()
end end
end
return self.status return self.status
end end
} }

View File

@ -1,14 +1,14 @@
-- Copyright (c) 2020-2021 shadmansaleh -- Copyright (c) 2020-2021 shadmansaleh
-- MIT license, see LICENSE for more details. -- MIT license, see LICENSE for more details.
local utils = require('lualine.utils.utils')
local Branch = require('lualine.component'):new() local Branch = require('lualine.component'):new()
-- vars -- vars
Branch.git_branch = '' Branch.git_branch = ''
-- os specific path separator -- os specific path separator
Branch.sep = package.config:sub(1, 1) Branch.sep = package.config:sub(1, 1)
-- event watcher to watch head file -- event watcher to watch head file
Branch.file_changed = vim.loop.new_fs_event() Branch.file_changed = vim.loop.new_fs_event()
local branch_cache = {} -- stores last known branch for a buffer
-- Initilizer -- Initilizer
Branch.new = function(self, options, child) Branch.new = function(self, options, child)
local new_branch = self._parent:new(options, child or Branch) local new_branch = self._parent:new(options, child or Branch)
@ -18,11 +18,14 @@ Branch.new = function(self, options, child)
-- run watch head on load so branch is present when component is loaded -- run watch head on load so branch is present when component is loaded
Branch.update_branch() Branch.update_branch()
-- update branch state of BufEnter as different Buffer may be on different repos -- update branch state of BufEnter as different Buffer may be on different repos
vim.cmd [[autocmd lualine BufEnter * lua require'lualine.components.branch'.update_branch()]] utils.define_autocmd('BufEnter', "lua require'lualine.components.branch'.update_branch()")
return new_branch return new_branch
end end
Branch.update_status = function() return Branch.git_branch end Branch.update_status = function(_, is_focused)
if not is_focused then return branch_cache[vim.fn.bufnr()] or '' end
return Branch.git_branch
end
-- returns full path to git directory for current directory -- returns full path to git directory for current directory
function Branch.find_git_dir() function Branch.find_git_dir()
@ -90,6 +93,7 @@ function Branch.update_branch()
-- set to '' when git dir was not found -- set to '' when git dir was not found
Branch.git_branch = '' Branch.git_branch = ''
end end
branch_cache[vim.fn.bufnr()] = Branch.git_branch
end end
return Branch return Branch

View File

@ -20,6 +20,8 @@ Diff.default_colors = {
modified = '#ff0038' modified = '#ff0038'
} }
local diff_cache = {} -- Stores last known value of diff of a buffer
-- Initializer -- Initializer
Diff.new = function(self, options, child) Diff.new = function(self, options, child)
local new_instance = self._parent:new(options, child or Diff) local new_instance = self._parent:new(options, child or Diff)
@ -64,22 +66,22 @@ Diff.new = function(self, options, child)
if type(new_instance.options.source) ~= 'function' then if type(new_instance.options.source) ~= 'function' then
-- setup internal source -- setup internal source
vim.cmd [[ utils.define_autocmd('BufEnter', "lua require'lualine.components.diff'.update_diff_args()")
autocmd lualine BufEnter * lua require'lualine.components.diff'.update_diff_args() utils.define_autocmd('BufWritePost', "lua require'lualine.components.diff'.update_git_diff()")
autocmd lualine BufWritePost * lua require'lualine.components.diff'.update_git_diff()
]]
end end
return new_instance return new_instance
end end
-- Function that runs everytime statusline is updated -- Function that runs everytime statusline is updated
Diff.update_status = function(self) Diff.update_status = function(self, is_focused)
local git_diff = Diff.git_diff
if self.options.source then if self.options.source then
Diff.git_diff = self.options.source() git_diff = self.options.source()
end end
if Diff.git_diff == nil then return '' end if not is_focused then git_diff = diff_cache[vim.fn.bufnr()] or {} end
if git_diff == nil then return '' end
local colors = {} local colors = {}
if self.options.colored then if self.options.colored then
@ -92,12 +94,12 @@ Diff.update_status = function(self)
local result = {} local result = {}
-- loop though data and load available sections in result table -- loop though data and load available sections in result table
for _, name in ipairs {'added', 'modified', 'removed'} do for _, name in ipairs {'added', 'modified', 'removed'} do
if Diff.git_diff[name] and Diff.git_diff[name] > 0 then if git_diff[name] and git_diff[name] > 0 then
if self.options.colored then if self.options.colored then
table.insert(result, colors[name] .. self.options.symbols[name] .. table.insert(result, colors[name] .. self.options.symbols[name] ..
Diff.git_diff[name]) git_diff[name])
else else
table.insert(result, self.options.symbols[name] .. Diff.git_diff[name]) table.insert(result, self.options.symbols[name] .. git_diff[name])
end end
end end
end end
@ -180,6 +182,7 @@ function Diff.update_diff_args()
else else
Diff.git_diff = {added = 0, modified = 0, removed = 0} Diff.git_diff = {added = 0, modified = 0, removed = 0}
end end
diff_cache[vim.fn.bufnr()] = Diff.git_diff
end end
} }
Diff.update_git_diff() Diff.update_git_diff()

View File

@ -2,8 +2,6 @@
-- MIT license, see LICENSE for more details. -- MIT license, see LICENSE for more details.
local FileName = require('lualine.component'):new() local FileName = require('lualine.component'):new()
FileName.inactive_eval = true
local function count(base, pattern) local function count(base, pattern)
return select(2, string.gsub(base, pattern, '')) return select(2, string.gsub(base, pattern, ''))
end end

View File

@ -30,7 +30,7 @@ function FileType:apply_icon()
if icon and self.options.colored then if icon and self.options.colored then
local highlight_color = utils.extract_highlight_colors( local highlight_color = utils.extract_highlight_colors(
icon_highlight_group, 'fg') icon_highlight_group, 'fg')
local is_focused = vim.g.statusline_winid == vim.fn.win_getid() local is_focused = utils.is_focused()
local default_highlight = highlight.format_highlight(is_focused, local default_highlight = highlight.format_highlight(is_focused,
self.options.self self.options.self
.section) .section)

View File

@ -1,8 +1,8 @@
local FunctionComponent = require('lualine.component'):new() local FunctionComponent = require('lualine.component'):new()
FunctionComponent.update_status = function(self) FunctionComponent.update_status = function(self, is_focused)
-- 1st element in options table is the function provided by config -- 1st element in options table is the function provided by config
return self.options[1]() return self.options[1](is_focused)
end end
return FunctionComponent return FunctionComponent

View File

@ -51,7 +51,7 @@ end
function M.create_highlight_groups(theme) function M.create_highlight_groups(theme)
utils.clear_highlights() utils.clear_highlights()
active_theme = theme active_theme = theme
if not vim.o.termguicolors then if not vim.opt.termguicolors:get() then
cterm_colors = require 'lualine.utils.cterm_colors' cterm_colors = require 'lualine.utils.cterm_colors'
end end
for mode, sections in pairs(theme) do for mode, sections in pairs(theme) do
@ -154,7 +154,7 @@ function M.component_format_highlight(highlight_name)
if highlight_name:find('no_mode') == #highlight_name - #'no_mode' + 1 then if highlight_name:find('no_mode') == #highlight_name - #'no_mode' + 1 then
return '%#' .. highlight_group .. '#' return '%#' .. highlight_group .. '#'
end end
if vim.g.statusline_winid == vim.fn.win_getid() then if utils.is_focused() then
highlight_group = append_mode(highlight_group) highlight_group = append_mode(highlight_group)
else else
highlight_group = highlight_group .. '_inactive' highlight_group = highlight_group .. '_inactive'

View File

@ -3,6 +3,7 @@
local highlight = require('lualine.highlight') local highlight = require('lualine.highlight')
local loader = require('lualine.utils.loader') local loader = require('lualine.utils.loader')
local utils_section = require('lualine.utils.section') local utils_section = require('lualine.utils.section')
local utils = require('lualine.utils.utils')
local config_module = require('lualine.config') local config_module = require('lualine.config')
local config = config_module.config local config = config_module.config
@ -145,9 +146,8 @@ end
local function status_dispatch() local function status_dispatch()
-- disable on specific filetypes -- disable on specific filetypes
local current_ft = vim.api.nvim_buf_get_option( local current_ft = vim.bo.filetype
vim.fn.winbufnr(vim.g.statusline_winid), 'filetype') local is_focused = utils.is_focused()
local is_focused = vim.g.statusline_winid == vim.fn.win_getid()
for _, ft in pairs(config.options.disabled_filetypes) do for _, ft in pairs(config.options.disabled_filetypes) do
if ft == current_ft then if ft == current_ft then
vim.wo.statusline = '' vim.wo.statusline = ''
@ -195,19 +195,17 @@ end
local function set_tabline() local function set_tabline()
if next(config.tabline) ~= nil then if next(config.tabline) ~= nil then
vim.o.tabline = '%!v:lua.require\'lualine\'.tabline()' vim.go.tabline = "%{%v:lua.require'lualine'.tabline()%}"
vim.o.showtabline = 2 vim.go.showtabline = 2
end end
end end
local function set_statusline() local function set_statusline()
if next(config.sections) ~= nil or next(config.inactive_sections) ~= nil then if next(config.sections) ~= nil or next(config.inactive_sections) ~= nil then
vim.o.statusline = '%!v:lua.require\'lualine\'.statusline()' vim.go.statusline = "%{%v:lua.require'lualine'.statusline()%}"
vim.api.nvim_exec([[ vim.cmd([[
autocmd lualine WinLeave,BufLeave * lua vim.wo.statusline=require'lualine'.statusline()
autocmd lualine BufWinEnter,WinEnter,BufEnter,SessionLoadPost * set statusline<
autocmd lualine VimResized * redrawstatus autocmd lualine VimResized * redrawstatus
]], false) ]])
end end
end end

View File

@ -1,6 +1,6 @@
-- Copyright (c) 2020-2021 shadmansaleh -- Copyright (c) 2020-2021 shadmansaleh
-- MIT license, see LICENSE for more details. -- MIT license, see LICENSE for more details.
-- Credit: itchyny(lightline) -- Credit: itchyny(lightline)
local background = vim.o.background local background = vim.opt.background:get()
return require('lualine.themes.papercolor_' .. background) return require('lualine.themes.papercolor_' .. background)

View File

@ -2,6 +2,6 @@
-- MIT license, see LICENSE for more details. -- MIT license, see LICENSE for more details.
-- Credit: itchyny(lightline) -- Credit: itchyny(lightline)
-- License: MIT License -- License: MIT License
local background = vim.o.background local background = vim.opt.background:get()
return require('lualine.themes.solarized_' .. background) return require('lualine.themes.solarized_' .. background)

View File

@ -15,7 +15,7 @@ function M.draw_section(section, section_name, is_focused)
(type(component) == 'table' and not component.component_no) then (type(component) == 'table' and not component.component_no) then
return '' -- unknown element in section. section posibly not yet loaded return '' -- unknown element in section. section posibly not yet loaded
end end
table.insert(status, component:draw(highlight_name)) table.insert(status, component:draw(highlight_name, is_focused))
end end
-- Flags required for knowing when to remove component separator -- Flags required for knowing when to remove component separator
@ -38,7 +38,6 @@ function M.draw_section(section, section_name, is_focused)
.options.section_separators[1]) .options.section_separators[1])
end end
end end
section[component_no].last_component = true
end end
-- Remove component separator when color option is used in next component -- Remove component separator when color option is used in next component
if strip_next_component then if strip_next_component then

View File

@ -56,14 +56,23 @@ function M.list_shrink(list)
return new_list return new_list
end end
-- Wvaluate a component -- Check if a auto command is already defined
function M.lualine_eval(id, ...) local function autocmd_is_defined(event, patern, command_str)
local ok, components = pcall(require, 'lualine.component.components') return vim.api.nvim_exec(string.format("au lualine %s %s",
if ok and components then event, patern), true):find(command_str) ~= nil
return components[id]:draw(...) end
else
return '' -- Define a auto command if it's not already defined
function M.define_autocmd(event, patern, cmd)
if not cmd then cmd = patern; patern = '*' end
if not autocmd_is_defined(event, patern, cmd) then
vim.cmd(string.format("autocmd lualine %s %s %s", event, patern, cmd))
end end
end end
-- Check if statusline is on focused window or not
function M.is_focused()
return tonumber(vim.g.actual_curwin) == vim.fn.win_getid()
end
return M return M