Skip to content

Commit

Permalink
feat(flexible_components):
Browse files Browse the repository at this point in the history
* improve cycling flexible componens logic (use while loop)
* standardize main evaluation loop for all statuslines
* allow flexible components and buflist in any statusline (statusline, winbar, tabline)
  • Loading branch information
rebelot committed Aug 29, 2022
1 parent ec0859e commit a726746
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 61 deletions.
50 changes: 29 additions & 21 deletions lua/heirline/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,50 +46,58 @@ function M.setup(statusline, winbar, tabline)

M.statusline = StatusLine:new(statusline)
vim.o.statusline = "%{%v:lua.require'heirline'.eval_statusline()%}"

if winbar then
M.winbar = StatusLine:new(winbar)
setup_local_winbar_with_autocmd()
end

if tabline then
M.tabline = StatusLine:new(tabline)
vim.o.showtabline = 2
vim.o.tabline = "%{%v:lua.require'heirline'.eval_tabline()%}"
end
end

local function _eval(statusline)
statusline.winnr = 1
statusline.flexible_components = {}
statusline._buflist = {}
local out = statusline:eval()
local buflist = statusline._buflist[1]

-- flexible components adapting to full-width buflist, shrinking them to the maximum if greater than vim.o.columns
utils.expand_or_contract_flexible_components(statusline.flexible_components, true, out)

if buflist then
out = statusline:traverse() -- this is now the tabline, after expansion/contraction
-- the space to render the buflist is "columns - (all_minus_fullwidthbuflist)"
buflist._maxwidth = vim.o.columns - (utils.count_chars(out) - utils.count_chars(buflist:traverse()))
utils.page_buflist(buflist)
out = statusline:traverse()

-- now the buflist is paged, and flexible components still have the same value, however, there might be more space now, depending on the page
utils.expand_or_contract_flexible_components(statusline.flexible_components, true, out) -- flexible components are re-adapting to paginated buflist
end
return statusline:traverse()
end

---@return string
function M.eval_statusline()
M.statusline.winnr = vim.api.nvim_win_get_number(0)
M.statusline.flexible_components = {}
local out = M.statusline:eval()
utils.expand_or_contract_flexible_components(M.statusline.flexible_components, vim.o.laststatus == 3, out)
return M.statusline:traverse()
return _eval(M.statusline)
end

---@return string
function M.eval_winbar()
M.winbar.winnr = vim.api.nvim_win_get_number(0)
M.winbar.flexible_components = {}
local out = M.winbar:eval()
utils.expand_or_contract_flexible_components(M.winbar.flexible_components, false, out)
return M.winbar:traverse()
return _eval(M.winbar)
end

---@return string
function M.eval_tabline()
M.tabline.winnr = 1
M.tabline.flexible_components = {}
M.tabline._buflist = {}
local out = M.tabline:eval()
local buflist = M.tabline._buflist[1]
if buflist then
buflist._maxwidth = vim.o.columns - (utils.count_chars(out) - utils.count_chars(buflist:traverse()))
utils.page_buflist(buflist)
end
-- utils.expand_or_contract_flexible_components(M.tabline.flexible_components, true, out)
return M.tabline:traverse()
return _eval(M.tabline)
end


-- test [[
function M.timeit()
local start = os.clock()
Expand Down
98 changes: 58 additions & 40 deletions lua/heirline/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ local function group_flexible_components(flexible_components, mode)
if not priorities[priority] then
table.insert(priorities, priority)
end

local comp = mode == -1 and function(a, b)
return a < b
end or function(a, b)
return a > b
end
table.sort(priorities, comp)
end
return priority_groups, priorities
end
Expand All @@ -205,67 +212,79 @@ function M.expand_or_contract_flexible_components(flexible_components, full_widt

if stl_len > winw then
local priority_groups, priorities = group_flexible_components(flexible_components, -1)
table.sort(priorities, function(a, b)
return a < b
end)

local saved_chars = 0

for _, p in ipairs(priorities) do
for _, component in ipairs(priority_groups[p]) do
-- try increasing the child index and return success
if next_child(component) then
local prev_len = M.count_chars(component:traverse())
local cur_len = M.count_chars(component:eval())
-- component:clear_tree()
-- component._tree[1] = component[component:get_win_attr("_win_child_index")]:traverse()
saved_chars = saved_chars + (prev_len - cur_len)
while true do
local out_of_components = true
for _, component in ipairs(priority_groups[p]) do
-- try increasing the child index and return success
if next_child(component) then
out_of_components = false
local prev_len = M.count_chars(component:traverse())
local cur_len = M.count_chars(component:eval())
-- component:clear_tree()
-- component._tree[1] = component[component:get_win_attr("_win_child_index")]:traverse()
saved_chars = saved_chars + (prev_len - cur_len)
end
end

if stl_len - saved_chars <= winw then
return
end
end

if stl_len - saved_chars <= winw then
return
if out_of_components then
break
end
end
end
elseif stl_len < winw then
local gained_chars = 0

local priority_groups, priorities = group_flexible_components(flexible_components, 1)
table.sort(priorities, function(a, b)
return a > b
end)

for _, p in ipairs(priorities) do
for _, component in ipairs(priority_groups[p]) do
if prev_child(component) then
local prev_len = M.count_chars(component:traverse())
local cur_len = M.count_chars(component:eval())
-- component:clear_tree()
gained_chars = gained_chars + (cur_len - prev_len)
while true do
local out_of_components = true
for _, component in ipairs(priority_groups[p]) do
if prev_child(component) then
out_of_components = false
local prev_len = M.count_chars(component:traverse())
local cur_len = M.count_chars(component:eval())
-- component:clear_tree()
gained_chars = gained_chars + (cur_len - prev_len)
end
end
end

if stl_len + gained_chars > winw then
for _, component in ipairs(priority_groups[p]) do
next_child(component)
-- here we need to manually reset the component tree, as we are increasing the
-- child index but without calling eval (wich should handle that);
-- since we went "one index too little", the next-index child tree has been already evaluated
-- in the previous loop.
component:clear_tree()
component._tree[1] = component[component:get_win_attr("_win_child_index")]:traverse()
if stl_len + gained_chars > winw then
for _, component in ipairs(priority_groups[p]) do
next_child(component)
-- here we need to manually reset the component tree, as we are increasing the
-- child index but without calling eval (wich should handle that);
-- since we went "one index too little", the next-index child tree has been already evaluated
-- in the previous loop.
component:clear_tree()
component._tree[1] = component[component:get_win_attr("_win_child_index")]:traverse()
end
return
end
if out_of_components then
break
end
return
end
end
end
end

function M.pick_child_on_condition(self)
self.pick_child = {}
for i, child in ipairs(self) do
--- Utility function to set component.pick_child on the first child that has a true condition,
--- this must be called within the component init.
---@param component table
function M.pick_child_on_condition(component)
component.pick_child = {}
for i, child in ipairs(component) do
if not child.condition or child:condition() then
table.insert(self.pick_child, i)
table.insert(component.pick_child, i)
return
end
end
Expand Down Expand Up @@ -416,7 +435,7 @@ end
--- Private function
---@param buflist table
function M.page_buflist(buflist)
if #buflist == 0 then
if not buflist or #buflist == 0 then
return
end

Expand Down Expand Up @@ -492,7 +511,6 @@ function M.on_colorscheme(colors)
require("heirline").statusline:broadcast(function(self)
self._win_cache = nil
end)

end

return M

0 comments on commit a726746

Please sign in to comment.