Skip to content

Commit

Permalink
chore: almost there
Browse files Browse the repository at this point in the history
  • Loading branch information
shortcuts committed Apr 30, 2024
1 parent 9883fe7 commit 55c650f
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 77 deletions.
27 changes: 13 additions & 14 deletions lua/no-neck-pain/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,11 @@ function N.enable(scope)
then
S.refreshTabs(S, S.activeTab)
D.log(p.event, "tab %d is now inactive", S.activeTab)
else
D.log(p.event, "tab %d left", S.activeTab)

return
end

D.log(p.event, "tab %d left", S.activeTab)
end)
end,
group = augroupName,
Expand Down Expand Up @@ -271,36 +273,33 @@ function N.enable(scope)
vim.api.nvim_create_autocmd({ "WinClosed", "BufDelete" }, {
callback = function(p)
vim.schedule(function()
if E.skip(nil) or not S.hasVSplits(S) or W.stateWinsActive() then
vim.print(E.skip(nil))
vim.print(not S.hasVSplits(S))
if E.skip(nil) or not S.hasVSplits(S) then
return
end

S.refreshVSplits(S)

-- we keep track if curr have been closed because if it's the case,
-- the focus will be on a side buffer which is wrong
local haveCloseCurr = false

-- if curr is not valid anymore, we focus the first valid split and remove it from the state
if not vim.api.nvim_win_is_valid(S.getSideID(S, "curr")) then
D.log(p.event, "curr has been closed")

-- if neither curr and splits are remaining valids, we just disable
if not S.hasVSplits(S) then
return N.disable(p.event)
end

haveCloseCurr = true

for _, split in pairs(S.tabs[S.activeTab].wins.splits) do
if vim.api.nvim_win_is_valid(split.id) then
S.setSideID(S, split.id, "curr")
S.refreshSplits(S)
break
end
end
-- TODO: find an other win if curr is closed
end

-- we only restore focus on curr if there's no split left
N.init(p.event, haveCloseCurr or not S.hasVSplits(S))
if S.checkSides(S, "or", true) then
N.init(p.event, haveCloseCurr or not S.hasVSplits(S))
end
end)
end,
group = augroupName,
Expand Down
47 changes: 35 additions & 12 deletions lua/no-neck-pain/state.lua
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ function State:reopenIntegration()
end
end

---Gets all integrations.
---
---@return table: the integration infos.
---@private
function State:getIntegrations()
return self.tabs[self.activeTab].wins.integrations
end

---Gets the integration with the given `win` if it's already registered.
---
---@param id integer: the integration to search for.
Expand Down Expand Up @@ -518,39 +526,54 @@ function State:increaseVSplits(nb)
self.tabs[self.activeTab].wins.vsplits = self.tabs[self.activeTab].wins.vsplits + nb
end

function State:iterateOverLayout(parent, curr)
local vsplit = false
parent = parent or false

---Recursively iterates over the `winlayout` until it has computed every column present in the UI.
---
---When we find a `row`, we set `vsplit` to true, the next element will always be a `table` so once on it -we can increase the `vsplits` counter.
---
---In order to also compute nested vsplits, we need to keep track how deep we are in the layout, we remove
---that depth from the number of elements in the current `row` in order to avoid counting all parents many times.
---
---@private
function State:iterateOverLayout(depth, vsplit, curr)
for _, group in ipairs(curr) do
-- a row indicates a `vsplit` window container
if type(group) == "string" and group == "row" then
vsplit = true
elseif type(group) == "table" then
local len = #group
if vsplit then
local length = parent and #group - 1 or #group
vim.print(length, parent, #group)
self.increaseVSplits(self, length)
end
-- even if we are super deep in the field, len minimal value is always 1.
if len <= depth then
len = depth + 1
end

self.iterateOverLayout(self, vsplit, group)
-- we remove the depth from the len in order to avoid counting parents multiple times.
self.increaseVSplits(self, len - depth)

-- reset vsplit as this layer as been computed already, increase depth as we will dug again.
depth = depth + 1
vsplit = false
end
self.iterateOverLayout(self, depth, vsplit, group)
end
end
end

---Refresh vsplits counter based on the `winlayout`.
---
---@param scope string: the caller of the method.
---@private
function State:refreshVSplits()
function State:refreshVSplits(scope)
self.initVSplits(self)

local layout = vim.fn.winlayout(self.activeTab)
if #layout == 2 and type(layout[1]) == "string" and type(layout[2]) == "number" then
self.increaseVSplits(self, 1)
else
self.iterateOverLayout(self, nil, layout)
self.iterateOverLayout(self, 0, false, layout)
end

D.log("refreshVSplits", "computed %d", self.tabs[self.activeTab].wins.vsplits)
D.log(scope, "computed %d", self.tabs[self.activeTab].wins.vsplits)
end

return State
81 changes: 30 additions & 51 deletions lua/no-neck-pain/wins.lua
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ end
function W.createSideBuffers(skipIntegrations)
-- before creating side buffers, we determine if we should consider externals
S.refreshIntegrations(S, "createSideBuffers")
S.refreshVSplits(S)
S.refreshVSplits(S, "createSideBuffers")

local wins = {
left = { cmd = "topleft vnew", padding = 0 },
Expand Down Expand Up @@ -190,6 +190,7 @@ end
---@return number: the width of the side window.
---@private
function W.getPadding(side)
local scope = string.format("W.getPadding:%s", side)
local uis = vim.api.nvim_list_uis()

if uis[1] == nil then
Expand All @@ -200,85 +201,63 @@ function W.getPadding(side)

local width = uis[1].width

D.log(scope, "screen width %d", width)

-- if the available screen size is lower than the config width,
-- we don't have to create side buffers.
if _G.NoNeckPain.config.width >= width then
D.log("W.getPadding", "[%s] - ui %s - no space left to create side buffers", side, width)
D.log(scope, "no space left to create side buffers", side, width)

return 0
end

local tab = S.getTab(S)
local columns = S.getVSplits(S)

if _G.NoNeckPain.config.buffers.left.enabled then
columns = columns - 1
end

if _G.NoNeckPain.config.buffers.right.enabled then
columns = columns - 1
end

if columns < 1 then
columns = 1
end

-- we need to see if there's enough space left to have side buffers
local occupied = _G.NoNeckPain.config.width * tab.wins.vsplits
local occupied = _G.NoNeckPain.config.width * columns

D.log(scope, "have %d vsplits", columns)

-- if there's no space left according to the config width,
-- then we don't have to create side buffers.
if occupied >= width then
D.log(side, "%d vsplits - no space left to create side buffers", tab.wins.vsplits)
D.log(scope, "%d occupied - no space left to create side", occupied)

return 0
end

D.log(
side,
"%d currently with %d vsplits - computing integrations width",
occupied,
tab.wins.vsplits
)
D.log(scope, "%d/%d with vsplits, computing integrations", occupied, width)

-- now we need to determine how much we should substract from the remaining padding
-- if there's side integrations open.
local paddingToSubstract = 0

for name, tree in pairs(tab.wins.integrations) do
for name, tree in pairs(S.getIntegrations(S)) do
if
tree.id ~= nil
and (not S.wantsSides(S) or side == _G.NoNeckPain.config.integrations[name].position)
then
D.log(
"W.getPadding",
"[%s] - have an external open: %s with width %d",
side,
name,
tree.width
)

-- TODO: do not store width, get it at runtime instead.
paddingToSubstract = paddingToSubstract + tree.width
end
end

return math.floor(
(width - paddingToSubstract - (_G.NoNeckPain.config.width * (tab.wins.vsplits - 2))) / 2
)
end
D.log(scope, "%s opened with width %d", name, tree.width)

---Determine if the tab wins are still active and valid.
---
---@return boolean: whether all windows are active and valid or not.
---@private
function W.stateWinsActive()
if not S.isActiveTabValid(S) then
return false
occupied = occupied + tree.width
end
end

local tab = S.getTabSafe(S)

if tab == nil then
return false
end
local final = math.floor((width - occupied) / 2)

if tab.wins.main ~= nil then
for _, side in pairs(tab.wins.main) do
if not vim.api.nvim_win_is_valid(side) then
return false
end
end
end
D.log(scope, "%d/%d with integrations - final %d", occupied, width, final)

return true
return final
end

return W

0 comments on commit 55c650f

Please sign in to comment.