Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lua/peekstack/core/events.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ local function debounced_reflow()
reflow_timer:stop()
vim.schedule(function()
stack.reflow_all()
require("peekstack.ui.stack_view").resize_all()
end)
end)
end
Expand Down
10 changes: 10 additions & 0 deletions lua/peekstack/ui/stack_view/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,16 @@ function M.refresh_all()
end
end

---Resize and re-render all open stack views (called on VimResized/WinResized).
function M.resize_all()
for _, s in pairs(states) do
if is_open(s) and s.winid and vim.api.nvim_win_is_valid(s.winid) then
vim.api.nvim_win_set_config(s.winid, stack_view_win_config())
render_state(s)
end
end
end

---Get stack view state (for testing).
---@return PeekstackStackViewState
function M._get_state()
Expand Down
95 changes: 95 additions & 0 deletions tests/layout_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,101 @@ describe("layout.compute", function()
assert.equals(first.row, second.row)
assert.equals(first.col, second.col)
end)

it("clamps to min_size on very small screen", function()
vim.o.columns = 30
vim.o.lines = 10
config.setup({
ui = {
layout = {
style = "stack",
offset = { row = 1, col = 4 },
shrink = { w = 4, h = 2 },
min_size = { w = 60, h = 12 },
max_ratio = 0.65,
zindex_base = 50,
},
},
})

local result = layout.compute(1)
assert.equals(30, result.width) -- clamped to columns (< min_size.w)
assert.equals(9, result.height) -- clamped to lines (< min_size.h)
assert.is_true(result.row >= 0)
assert.is_true(result.col >= 0)
end)

it("produces non-negative row and col for all indices", function()
vim.o.columns = 40
vim.o.lines = 15
config.setup({
ui = {
layout = {
style = "stack",
offset = { row = 1, col = 4 },
shrink = { w = 4, h = 2 },
min_size = { w = 20, h = 6 },
max_ratio = 0.65,
zindex_base = 50,
},
},
})

for idx = 1, 5 do
local result = layout.compute(idx)
assert.is_true(result.width > 0, "width should be positive at index " .. idx)
assert.is_true(result.height > 0, "height should be positive at index " .. idx)
assert.is_true(result.row >= 0, "row should be non-negative at index " .. idx)
assert.is_true(result.col >= 0, "col should be non-negative at index " .. idx)
end
end)
end)

describe("layout.reflow", function()
before_each(function()
stack._reset()
config.setup({})
end)

after_each(function()
local s = stack.current_stack()
for i = #s.popups, 1, -1 do
stack.close(s.popups[i].id)
end
stack._reset()
end)

it("does not error on empty stack", function()
local s = stack.current_stack()
assert.equals(0, #s.popups)
assert.has_no.errors(function()
layout.reflow(s)
end)
end)

it("recalculates popup dimensions after screen size change", function()
local original_columns = vim.o.columns
local original_lines = vim.o.lines

local loc = helpers.make_location()
local m1 = stack.push(loc)
assert.is_not_nil(m1)

local cfg_before = vim.api.nvim_win_get_config(m1.winid)

-- Simulate screen resize
vim.o.columns = math.floor(original_columns / 2)
vim.o.lines = math.floor(original_lines / 2)

local s = stack.current_stack()
layout.reflow(s)

local cfg_after = vim.api.nvim_win_get_config(m1.winid)
assert.is_true(cfg_after.width <= cfg_before.width)

vim.o.columns = original_columns
vim.o.lines = original_lines
end)
end)

describe("layout.update_focus_zindex", function()
Expand Down
23 changes: 23 additions & 0 deletions tests/stack_view_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,29 @@ describe("peekstack.ui.stack_view", function()
stack._reset()
end)

it("resize_all updates open stack view dimensions", function()
local original_columns = vim.o.columns

stack_view.open()
local state = stack_view._get_state()
local cfg_before = vim.api.nvim_win_get_config(state.winid)

-- Simulate wider screen
vim.o.columns = original_columns + 40
stack_view.resize_all()

local cfg_after = vim.api.nvim_win_get_config(state.winid)
assert.is_true(cfg_after.width >= cfg_before.width)

vim.o.columns = original_columns
end)

it("resize_all does not error when stack view is closed", function()
assert.has_no.errors(function()
stack_view.resize_all()
end)
end)

it("filters stack entries by query", function()
local root_winid = vim.api.nvim_get_current_win()
local s = stack.current_stack(root_winid)
Expand Down
21 changes: 21 additions & 0 deletions tests/toggle_visibility_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,27 @@ describe("stack.toggle_visibility", function()
assert.equals(0, #s.popups)
end)

it("reflow_all skips hidden stack without error", function()
local loc = helpers.make_location()
stack.push(loc)
stack.push(loc)

stack.toggle_visibility()
assert.is_true(stack.is_hidden())

-- reflow_all should skip hidden popups (winid=nil) safely
assert.has_no.errors(function()
stack.reflow_all()
end)

-- Popups should still be in the stack
local s = stack.current_stack()
assert.equals(2, #s.popups)
for _, item in ipairs(s.popups) do
assert.is_nil(item.winid)
end
end)

it("does not leak popups to history when hiding", function()
local loc = helpers.make_location()
stack.push(loc)
Expand Down