Skip to content

Commit

Permalink
fix: inconsistent walking
Browse files Browse the repository at this point in the history
  • Loading branch information
shortcuts committed Jul 2, 2024
1 parent 4194778 commit 6d74bb4
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 45 deletions.
2 changes: 1 addition & 1 deletion lua/no-neck-pain/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ function N.enable(scope)
return D.log(p.event, "skip")
end

S.refreshVSplits(S, scope)
S.refreshVSplits(S, p.event)

if S.wantsSides(S) and S.checkSides(S, "and", false) then
return D.log(p.event, "no side buffer")
Expand Down
68 changes: 34 additions & 34 deletions lua/no-neck-pain/state.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,20 @@ function State:save()
_G.NoNeckPain.state = self
end

---Sets the vsplits counter to 1.
---Initializes the vsplits to an empty table.
---
---@private
function State:initVSplits()
self.tabs[self.activeTab].wins.vsplits = 0
self.tabs[self.activeTab].wins.vsplits = {}
end

---Gets the tab vsplits counter.
---
---@return number: the number of active vsplits.
---@return table: the vsplits window IDs.
---@return number: the number of vsplits.
---@private
function State:getVSplits()
return self.tabs[self.activeTab].wins.vsplits
return self.tabs[self.activeTab].wins.vsplits, A.length(self.tabs[self.activeTab].wins.vsplits)
end

---Whether the side is enabled in the config or not.
Expand Down Expand Up @@ -489,7 +490,7 @@ function State:setTab(id)
id = id,
scratchPadEnabled = false,
wins = {
vsplits = 0,
vsplits = {},
main = {
curr = nil,
left = nil,
Expand All @@ -501,12 +502,17 @@ function State:setTab(id)
self.activeTab = id
end

---Increases the vsplits counter.
---Insert the given ids window ids in the state.
---
---@param nb number: the number of columns in the given row.
---@param vsplits table: the vsplits leafs to add to the state.
---@private
function State:increaseVSplits(nb)
self.tabs[self.activeTab].wins.vsplits = self.tabs[self.activeTab].wins.vsplits + nb
function State:insertVSplits(vsplits)
for _, vsplit in ipairs(vsplits) do
-- only add the leaf because we can receive something like { "col" {...}}, which will then be walked in and inserted later
if vsplit[1] == "leaf" then
self.tabs[self.activeTab].wins.vsplits[vsplit[2]] = true
end
end
end

---Recursively walks in the `winlayout` until it has computed every column present in the UI.
Expand All @@ -517,51 +523,45 @@ end
---that depth from the number of elements in the current `row` in order to avoid counting all parents many times.
---
---@private
function State:walkLayout(depth, vsplit, curr)
function State:walkLayout(parent, 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
-- even if we are super deep in the field, len minimal value is always 1.
if len <= depth then
len = depth + 1
end

if type(group) == "table" then
-- a row indicates a `vsplit` window container
if parent == "row" then
-- 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
self.insertVSplits(self, group)
parent = nil
end
self.walkLayout(self, depth, vsplit, group)
self.walkLayout(self, parent, group)
-- depth 0 on a leaf is only possible after enabling nnp as there's nothing in the layout other than the main window
elseif depth == 0 and group == "leaf" then
self.increaseVSplits(self, 1)
elseif group == "leaf" and parent == nil then
self.insertVSplits(self, { curr })
elseif type(group) == "string" then
parent = group
end
end
end

---Refresh vsplits counter based on the `winlayout`.
---Refresh vsplits state based on the `winlayout`.
---
---@param scope string: the caller of the method.
---@return boolean: whether the number of vsplits changed or not.
---@private
function State:refreshVSplits(scope)
local currentVSplits = self.getVSplits(self)
local _, nbVSplits = self.getVSplits(self)

self.initVSplits(self)

self.walkLayout(self, 0, false, vim.fn.winlayout(self.activeTab))
self.walkLayout(self, nil, vim.fn.winlayout(self.activeTab))

D.log(scope, "computed %d vsplits", self.getVSplits(self))
D.log(scope, "computed %d vsplits", nbVSplits)

self.save(self)

return currentVSplits ~= self.getVSplits(self)
local _, nbNBVsplits = self.getVSplits(self)

-- TODO: real table diff
return nbVSplits ~= nbNBVsplits
end

return State
31 changes: 24 additions & 7 deletions lua/no-neck-pain/wins.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ local W = {}
---
---@param id number: the id of the window.
---@param width number: the width to apply to the window.
---@param side "left"|"right"|"curr": the side of the window being resized, used for logging only.
---@param side "left"|"right"|"curr"|"vsplit": the side of the window being resized, used for logging only.
---@private
local function resize(id, width, side)
D.log(side, "resizing %d with padding %d", id, width)
Expand Down Expand Up @@ -177,6 +177,27 @@ function W.createSideBuffers(skipIntegrations)
end
end

local vsplits, nbVSplits = S.getVSplits(S)
local leftID = S.getSideID(S, "left")
local rightID = S.getSideID(S, "right")

-- if we still have side buffers open at this point, and we have vsplit opened,
-- there might be width issues so we the resize opened vsplits.
if (leftID or rightID) and nbVSplits > 0 then
local sWidth = wins.left.padding or wins.right.padding
local nbSide = leftID and rightID and 2 or 1

-- get the available usable width (screen size without side paddings)
sWidth = vim.api.nvim_list_uis()[1].width - sWidth * nbSide
sWidth = math.floor(sWidth / (nbVSplits - nbSide))

for vsplit, _ in pairs(vsplits) do
if vsplit ~= leftID and vsplit ~= rightID and vsplit ~= S.getSideID(S, "curr") then
resize(vsplit, sWidth, "vsplit")
end
end
end

-- closing integrations and reopening them means new window IDs
if closedIntegrations then
S.refreshIntegrations(S, "createSideBuffers")
Expand Down Expand Up @@ -208,18 +229,14 @@ function W.getPadding(side)
return 0
end

local columns = S.getVSplits(S)
local _, columns = S.getVSplits(S)

for _, s in ipairs(Co.SIDES) do
if S.isSideEnabled(S, s) then
if S.isSideEnabled(S, s) and columns > 1 then
columns = columns - 1
end
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 * columns

Expand Down
8 changes: 5 additions & 3 deletions tests/test_API.lua
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ T["enable"]["(single tab) sets state"] = function()
right = 1002,
})

Helpers.expect.state(child, "tabs[1].wins.vsplits", 1)
Helpers.expect.state(child, "tabs[1].wins.vsplits[1000]", true)

Helpers.expect.state_type(child, "tabs[1].wins.integrations", "table")

Expand Down Expand Up @@ -270,7 +270,7 @@ T["enable"]["(multiple tab) sets state"] = function()
left = 1001,
right = 1002,
})
Helpers.expect.state(child, "tabs[1].wins.vsplits", 1)
Helpers.expect.state(child, "tabs[1].wins.vsplits[1000]", true)

Helpers.expect.state_type(child, "tabs[1].wins.integrations", "table")

Expand All @@ -294,7 +294,9 @@ T["enable"]["(multiple tab) sets state"] = function()
left = 1004,
right = 1005,
})
Helpers.expect.state(child, "tabs[2].wins.vsplits", 3)
Helpers.expect.state(child, "tabs[2].wins.vsplits[1003]", true)
Helpers.expect.state(child, "tabs[2].wins.vsplits[1004]", true)
Helpers.expect.state(child, "tabs[2].wins.vsplits[1005]", true)

Helpers.expect.state_type(child, "tabs[2].wins.integrations", "table")

Expand Down

0 comments on commit 6d74bb4

Please sign in to comment.