Skip to content
Open
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ https://github.com/user-attachments/assets/64c41f01-dffe-4318-bce4-16eec8de356e

-- Explorer panel configuration
explorer = {
position = "left", -- "left" or "bottom"
position = "left", -- "left", "right", "top", or "bottom"
hidden = false, -- Initial visibility state
width = 40, -- Width when position is "left" (columns)
height = 15, -- Height when position is "bottom" (lines)
Expand Down Expand Up @@ -135,7 +135,7 @@ https://github.com/user-attachments/assets/64c41f01-dffe-4318-bce4-16eec8de356e

-- History panel configuration (for :CodeDiff history)
history = {
position = "bottom", -- "left" or "bottom" (default: bottom)
position = "bottom", -- "left", "right", "top", or "bottom" (default: bottom)
width = 40, -- Width when position is "left" (columns)
height = 15, -- Height when position is "bottom" (lines)
initial_focus = "history", -- Initial focus: "history", "original", or "modified"
Expand Down
4 changes: 2 additions & 2 deletions lua/codediff/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ M.defaults = {

-- Explorer panel configuration
explorer = {
position = "left", -- "left" or "bottom"
position = "left", -- "left", "right", "top", or "bottom"
hidden = false, -- Initial visibility state
width = 40, -- Width when position is "left" (columns)
height = 15, -- Height when position is "bottom" (lines)
Expand Down Expand Up @@ -79,7 +79,7 @@ M.defaults = {

-- History panel configuration (for :CodeDiff history)
history = {
position = "bottom", -- "left" or "bottom" (default: bottom)
position = "bottom", -- "left", "right", "top", or "bottom" (default: bottom)
width = 40, -- Width when position is "left" (columns)
height = 15, -- Height when position is "bottom" (lines)
initial_focus = "history", -- Initial focus: "history", "original", or "modified"
Expand Down
4 changes: 2 additions & 2 deletions lua/codediff/ui/explorer/render.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ function M.create(status_result, git_root, tabpage, width, base_revision, target
local size
local text_width -- Width for text rendering (always horizontal width)

if position == "bottom" then
if position == "bottom" or position == "top" then
size = explorer_config.height or 15
-- For bottom position, use full window width for text
-- For bottom/top position, use full window width for text
text_width = vim.o.columns
else
-- Use provided width or config width or default to 40 columns
Expand Down
2 changes: 1 addition & 1 deletion lua/codediff/ui/history/render.lua
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function M.create(commits, git_root, tabpage, width, opts)
local size
local text_width

if position == "bottom" then
if position == "bottom" or position == "top" then
size = history_config.height or 15
text_width = vim.o.columns
else
Expand Down
6 changes: 3 additions & 3 deletions lua/codediff/ui/layout.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function M.arrange(tabpage)

-- Step 1: Pin panel size (fixed element)
if panel_visible then
if panel_position == "left" then
if panel_position == "left" or panel_position == "right" then
vim.api.nvim_win_set_width(panel_win, panel_config.width)
else
vim.api.nvim_win_set_height(panel_win, panel_config.height)
Expand All @@ -51,7 +51,7 @@ function M.arrange(tabpage)
local sole_win = orig_valid and original_win or (mod_valid and modified_win or nil)
if sole_win then
if panel_visible then
if panel_position == "left" then
if panel_position == "left" or panel_position == "right" then
vim.api.nvim_win_set_width(panel_win, panel_config.width)
-- Explicitly set diff window to fill remainder
local remainder = vim.o.columns - panel_config.width - 1
Expand Down Expand Up @@ -117,7 +117,7 @@ function M.arrange(tabpage)

-- Step 5: Re-pin panel size (undo disturbance from step 4)
if panel_visible then
if panel_position == "left" then
if panel_position == "left" or panel_position == "right" then
vim.api.nvim_win_set_width(panel_win, panel_config.width)
else
vim.api.nvim_win_set_height(panel_win, panel_config.height)
Expand Down
152 changes: 152 additions & 0 deletions tests/ui/layout_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,82 @@ describe("Layout Manager", function()
cleanup_mock_session(tabpage)
end)

-- =========================================================================
-- Case 3b: Explorer right, no result — [orig | mod | expl]
-- =========================================================================
it("Case 3b: Explorer right — panel gets configured width, diff panes split remainder", function()
local panel_width = 35
config.options.explorer = { position = "right", width = panel_width }

vim.cmd("tabnew")
local tabpage = vim.api.nvim_get_current_tabpage()
local orig_win = vim.api.nvim_get_current_win()
local orig_buf = vim.api.nvim_get_current_buf()
vim.cmd("vsplit")
local mod_win = vim.api.nvim_get_current_win()
local mod_buf = vim.api.nvim_get_current_buf()

local panel = create_panel_split("right", panel_width)

create_mock_session(tabpage, {
mode = "explorer",
original_win = orig_win,
modified_win = mod_win,
original_bufnr = orig_buf,
modified_bufnr = mod_buf,
panel = panel,
})

layout.arrange(tabpage)

local panel_w = vim.api.nvim_win_get_width(panel.winid)
local orig_w = vim.api.nvim_win_get_width(orig_win)
local mod_w = vim.api.nvim_win_get_width(mod_win)

assert.are.equal(panel_width, panel_w, "Panel should be configured width")
assert_width_near(orig_w, mod_w, "Diff panes should be equal width:")

cleanup_mock_session(tabpage)
end)

-- =========================================================================
-- Case 3c: Explorer top, no result — [expl] / [orig | mod]
-- =========================================================================
it("Case 3c: Explorer top — panel gets configured height, diff panes split full width", function()
local panel_height = 12
config.options.explorer = { position = "top", height = panel_height }

vim.cmd("tabnew")
local tabpage = vim.api.nvim_get_current_tabpage()
local orig_win = vim.api.nvim_get_current_win()
local orig_buf = vim.api.nvim_get_current_buf()
vim.cmd("vsplit")
local mod_win = vim.api.nvim_get_current_win()
local mod_buf = vim.api.nvim_get_current_buf()

local panel = create_panel_split("top", panel_height)

create_mock_session(tabpage, {
mode = "explorer",
original_win = orig_win,
modified_win = mod_win,
original_bufnr = orig_buf,
modified_bufnr = mod_buf,
panel = panel,
})

layout.arrange(tabpage)

local panel_h = vim.api.nvim_win_get_height(panel.winid)
local orig_w = vim.api.nvim_win_get_width(orig_win)
local mod_w = vim.api.nvim_win_get_width(mod_win)

assert.are.equal(panel_height, panel_h, "Panel should be configured height")
assert_width_near(orig_w, mod_w, "Diff panes should be equal width:")

cleanup_mock_session(tabpage)
end)

-- =========================================================================
-- Case 4: History left, no result — [hist | orig | mod]
-- =========================================================================
Expand Down Expand Up @@ -336,6 +412,82 @@ describe("Layout Manager", function()
cleanup_mock_session(tabpage)
end)

-- =========================================================================
-- Case 5b: History right, no result — [orig | mod | hist]
-- =========================================================================
it("Case 5b: History right — panel gets configured width, diff panes split remainder", function()
local panel_width = 30
config.options.history = { position = "right", width = panel_width }

vim.cmd("tabnew")
local tabpage = vim.api.nvim_get_current_tabpage()
local orig_win = vim.api.nvim_get_current_win()
local orig_buf = vim.api.nvim_get_current_buf()
vim.cmd("vsplit")
local mod_win = vim.api.nvim_get_current_win()
local mod_buf = vim.api.nvim_get_current_buf()

local panel = create_panel_split("right", panel_width)

create_mock_session(tabpage, {
mode = "history",
original_win = orig_win,
modified_win = mod_win,
original_bufnr = orig_buf,
modified_bufnr = mod_buf,
panel = panel,
})

layout.arrange(tabpage)

local panel_w = vim.api.nvim_win_get_width(panel.winid)
local orig_w = vim.api.nvim_win_get_width(orig_win)
local mod_w = vim.api.nvim_win_get_width(mod_win)

assert.are.equal(panel_width, panel_w, "History panel should be configured width")
assert_width_near(orig_w, mod_w, "Diff panes should be equal width:")

cleanup_mock_session(tabpage)
end)

-- =========================================================================
-- Case 5c: History top, no result — [hist] / [orig | mod]
-- =========================================================================
it("Case 5c: History top — panel gets configured height, diff panes split full width", function()
local panel_height = 10
config.options.history = { position = "top", height = panel_height }

vim.cmd("tabnew")
local tabpage = vim.api.nvim_get_current_tabpage()
local orig_win = vim.api.nvim_get_current_win()
local orig_buf = vim.api.nvim_get_current_buf()
vim.cmd("vsplit")
local mod_win = vim.api.nvim_get_current_win()
local mod_buf = vim.api.nvim_get_current_buf()

local panel = create_panel_split("top", panel_height)

create_mock_session(tabpage, {
mode = "history",
original_win = orig_win,
modified_win = mod_win,
original_bufnr = orig_buf,
modified_bufnr = mod_buf,
panel = panel,
})

layout.arrange(tabpage)

local panel_h = vim.api.nvim_win_get_height(panel.winid)
local orig_w = vim.api.nvim_win_get_width(orig_win)
local mod_w = vim.api.nvim_win_get_width(mod_win)

assert.are.equal(panel_height, panel_h, "History panel should be configured height")
assert_width_near(orig_w, mod_w, "Diff panes should be equal width:")

cleanup_mock_session(tabpage)
end)

-- =========================================================================
-- Case 6: Explorer left + result bottom — [expl | orig | mod] / [result]
-- =========================================================================
Expand Down