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
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.41.1
2.42.0
10 changes: 8 additions & 2 deletions lua/codediff/ui/core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,14 @@ function M.render_diff(left_bufnr, right_bufnr, original_lines, modified_lines,
end

-- Render moved code indicators (separate module)
local move = require("codediff.ui.move")
move.render_moves(left_bufnr, right_bufnr, lines_diff)
if lines_diff.moves and #lines_diff.moves > 0 then
local ok, move = pcall(require, "codediff.ui.move")
if ok and move then
move.render_moves(left_bufnr, right_bufnr, lines_diff)
else
vim.notify_once("[codediff] failed to load codediff.ui.move: " .. tostring(move), vim.log.levels.WARN)
end
end

return {
left_fillers = total_left_fillers,
Expand Down
94 changes: 87 additions & 7 deletions lua/codediff/ui/explorer/refresh.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ local M = {}

local config = require("codediff.config")
local tree_module = require("codediff.ui.explorer.tree")
local welcome = require("codediff.ui.welcome")

-- Setup auto-refresh triggers for explorer
-- Returns a cleanup function that should be called when the explorer is destroyed
Expand Down Expand Up @@ -252,16 +253,95 @@ function M.refresh(explorer)
-- Update status result for file selection logic
explorer.status_result = status_result

-- Try to restore selection
if current_path then
local nodes = explorer.tree:get_nodes()
for _, node in ipairs(nodes) do
if node.data and node.data.path == current_path then
explorer.tree:set_node(node:get_id())
break
local function clear_current_file()
explorer.current_file_path = nil
explorer.current_file_group = nil
end

-- Helper: show the welcome page in the diff panes
local function show_welcome_page()
local lifecycle = require("codediff.ui.lifecycle")
local session = lifecycle.get_session(explorer.tabpage)
if session and not welcome.is_welcome_buffer(session.modified_bufnr) then
local mod_win = session.modified_win
if mod_win and vim.api.nvim_win_is_valid(mod_win) then
if session.layout == "inline" then
local w = vim.api.nvim_win_get_width(mod_win)
local h = vim.api.nvim_win_get_height(mod_win)
local welcome_buf = welcome.create_buffer(w, h)
require("codediff.ui.view.inline_view").show_welcome(explorer.tabpage, welcome_buf)
else
local orig_win = session.original_win
if orig_win and vim.api.nvim_win_is_valid(orig_win) then
local w = vim.api.nvim_win_get_width(orig_win) + vim.api.nvim_win_get_width(mod_win) + 1
local h = vim.api.nvim_win_get_height(orig_win)
local welcome_buf = welcome.create_buffer(w, h)
require("codediff.ui.view.side_by_side").show_welcome(explorer.tabpage, welcome_buf)
end
end
end
end
end

-- Show welcome page when all files are clean
local total_files = #(status_result.unstaged or {}) + #(status_result.staged or {}) + #(status_result.conflicts or {})
if total_files == 0 then
clear_current_file()
show_welcome_page()
end

-- Re-select the currently viewed file after refresh.
-- Search all file children across all groups for the current file.
-- If found (possibly in a new group), call on_file_select to update diff panes.
-- If not found (committed/removed), show welcome page.
if explorer.current_file_path and total_files > 0 then
local found_file = nil
local found_group = nil
-- Search helper: look in a specific status list
local function search_group(files, group_name)
for _, f in ipairs(files or {}) do
if f.path == explorer.current_file_path then
return f, group_name
end
end
return nil, nil
end
-- Search same group first (preferred — e.g. hunk staging keeps file in same group)
local current_group = explorer.current_file_group
if current_group then
local group_lists = {
unstaged = status_result.unstaged,
staged = status_result.staged,
conflicts = status_result.conflicts,
}
found_file, found_group = search_group(group_lists[current_group], current_group)
end
-- If not in same group, search all groups
if not found_file then
found_file, found_group = search_group(status_result.conflicts, "conflicts")
end
if not found_file then
found_file, found_group = search_group(status_result.unstaged, "unstaged")
end
if not found_file then
found_file, found_group = search_group(status_result.staged, "staged")
end

if found_file then
-- File still exists (possibly in a new group) — re-select it
explorer.on_file_select({
path = found_file.path,
old_path = found_file.old_path,
status = found_file.status,
git_root = explorer.git_root,
group = found_group,
})
else
-- File was committed/removed — show welcome
clear_current_file()
show_welcome_page()
end
end
end)
end

Expand Down
3 changes: 3 additions & 0 deletions lua/codediff/ui/lifecycle/cleanup.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ local M = {}
local accessors = require("codediff.ui.lifecycle.accessors")
local session = require("codediff.ui.lifecycle.session")
local state = require("codediff.ui.lifecycle.state")
local welcome_window = require("codediff.ui.view.welcome_window")

-- Autocmd group for cleanup
local augroup = vim.api.nvim_create_augroup("codediff_lifecycle", { clear = true })
Expand Down Expand Up @@ -92,9 +93,11 @@ local function cleanup_diff(tabpage)

-- Clear window variables if windows still exist
if vim.api.nvim_win_is_valid(diff.original_win) then
welcome_window.apply_normal(diff.original_win)
vim.w[diff.original_win].codediff_restore = nil
end
if vim.api.nvim_win_is_valid(diff.modified_win) then
welcome_window.apply_normal(diff.modified_win)
vim.w[diff.modified_win].codediff_restore = nil
end

Expand Down
27 changes: 17 additions & 10 deletions lua/codediff/ui/lifecycle/session.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ local M = {}
local config = require("codediff.config")
local virtual_file = require("codediff.core.virtual_file")
local accessors = require("codediff.ui.lifecycle.accessors")
local welcome_window = require("codediff.ui.view.welcome_window")

-- Track active diff sessions
-- Structure: {
Expand Down Expand Up @@ -110,6 +111,8 @@ function M.create_session(
reapply_keymaps = reapply_keymaps,
}

welcome_window.capture_session_profiles(active_diffs[tabpage])

-- Mark windows with restore flag
vim.w[original_win].codediff_restore = 1
vim.w[modified_win].codediff_restore = 1
Expand Down Expand Up @@ -141,29 +144,33 @@ function M.create_session(
end

-- Force disable winbar to prevent alignment issues (except in conflict mode)
local function ensure_no_winbar()
local sess = active_diffs[tabpage]
local function sync_window_ui(sess, win)
-- In conflict mode, preserve existing winbar titles (set by conflict_window.lua)
if sess and sess.result_win and vim.api.nvim_win_is_valid(sess.result_win) then
return
end
-- Normal diff mode: disable winbar
if vim.api.nvim_win_is_valid(original_win) then
vim.wo[original_win].winbar = ""
if sess and vim.api.nvim_win_is_valid(sess.original_win) then
vim.wo[sess.original_win].winbar = ""
end
if vim.api.nvim_win_is_valid(modified_win) then
vim.wo[modified_win].winbar = ""
if sess and vim.api.nvim_win_is_valid(sess.modified_win) then
vim.wo[sess.modified_win].winbar = ""
end
end

vim.api.nvim_create_autocmd({ "BufWinEnter", "FileType" }, {
vim.api.nvim_create_autocmd({ "BufWinEnter", "BufEnter", "WinEnter", "FileType" }, {
group = tab_augroup,
callback = function(args)
callback = function()
local sess = active_diffs[tabpage]
if not sess then
return
end
local win = vim.api.nvim_get_current_win()
if win == original_win or win == modified_win then
ensure_no_winbar()
if win == sess.original_win or win == sess.modified_win then
sync_window_ui(sess, win)
-- Re-apply critical window options that might get reset by ftplugins/autocmds
vim.wo[win].wrap = false
welcome_window.sync(win)
end
end,
})
Expand Down
42 changes: 42 additions & 0 deletions lua/codediff/ui/view/inline_view.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ local diff_module = require("codediff.core.diff")
local inline = require("codediff.ui.inline")
local semantic = require("codediff.ui.semantic_tokens")
local layout = require("codediff.ui.layout")
local welcome_window = require("codediff.ui.view.welcome_window")

local helpers = require("codediff.ui.view.helpers")
local panel = require("codediff.ui.view.panel")
Expand Down Expand Up @@ -105,6 +106,7 @@ function M.create(session_config, filetype, on_ready)
vim.bo[mod_scratch].buftype = "nofile"
pcall(vim.api.nvim_buf_set_name, mod_scratch, "CodeDiff " .. tabpage .. ".inline")
vim.api.nvim_win_set_buf(modified_win, mod_scratch)
welcome_window.sync(modified_win)

local orig_scratch = vim.api.nvim_create_buf(false, true)
vim.bo[orig_scratch].buftype = "nofile"
Expand Down Expand Up @@ -171,6 +173,7 @@ function M.create(session_config, filetype, on_ready)
else
vim.api.nvim_win_set_buf(modified_win, modified_info.bufnr)
end
welcome_window.sync(modified_win)

-- Load original buffer (hidden — never displayed in a window)
if original_is_virtual and original_info.needs_edit then
Expand Down Expand Up @@ -378,6 +381,7 @@ function M.update(tabpage, session_config, auto_scroll_to_first_hunk)
end
vim.api.nvim_win_set_buf(modified_win, mod_buf)
end
welcome_window.sync(modified_win)

local should_auto_scroll = auto_scroll_to_first_hunk == true

Expand Down Expand Up @@ -551,6 +555,7 @@ function M.show_single_file(tabpage, file_path, opts)
file_bufnr = vim.api.nvim_create_buf(false, true)
vim.bo[file_bufnr].buftype = "nofile"
vim.api.nvim_win_set_buf(mod_win, file_bufnr)
welcome_window.sync(mod_win)
local ft = vim.filetype.match({ filename = opts.rel_path or file_path })
if ft then
vim.bo[file_bufnr].filetype = ft
Expand All @@ -575,6 +580,7 @@ function M.show_single_file(tabpage, file_path, opts)
file_bufnr = vim.fn.bufadd(file_path)
vim.fn.bufload(file_bufnr)
vim.api.nvim_win_set_buf(mod_win, file_bufnr)
welcome_window.sync(mod_win)
end

-- Update session state
Expand All @@ -588,6 +594,42 @@ function M.show_single_file(tabpage, file_path, opts)

local view_keymaps = require("codediff.ui.view.keymaps")
view_keymaps.setup_all_keymaps(tabpage, empty_buf, file_bufnr, true)
welcome_window.sync_later(mod_win)
end

--- Show the welcome page in the inline diff window
---@param tabpage number
---@param load_bufnr number Welcome buffer created by welcome.create_buffer
function M.show_welcome(tabpage, load_bufnr)
local session = lifecycle.get_session(tabpage)
if not session then
return
end

local mod_win = session.modified_win
if not mod_win or not vim.api.nvim_win_is_valid(mod_win) then
return
end

if session.modified_bufnr and vim.api.nvim_buf_is_valid(session.modified_bufnr) then
inline.clear(session.modified_bufnr)
auto_refresh.disable(session.modified_bufnr)
end

vim.api.nvim_win_set_buf(mod_win, load_bufnr)
welcome_window.sync(mod_win)

local empty_buf = vim.api.nvim_create_buf(false, true)
vim.bo[empty_buf].buftype = "nofile"

lifecycle.update_buffers(tabpage, empty_buf, load_bufnr)
lifecycle.update_paths(tabpage, "", "")
lifecycle.update_revisions(tabpage, nil, nil)
lifecycle.update_diff_result(tabpage, {})

local view_keymaps = require("codediff.ui.view.keymaps")
view_keymaps.setup_all_keymaps(tabpage, empty_buf, load_bufnr, true)
welcome_window.sync_later(mod_win)
end

return M
8 changes: 6 additions & 2 deletions lua/codediff/ui/view/keymaps.lua
Original file line number Diff line number Diff line change
Expand Up @@ -683,9 +683,13 @@ function M.setup_all_keymaps(tabpage, original_bufnr, modified_bufnr, is_explore

-- Help keymap (g?) - show floating window with available keymaps
if keymaps.show_help then
local help = require("codediff.ui.keymap_help")
lifecycle.set_tab_keymap(tabpage, "n", keymaps.show_help, function()
help.toggle(tabpage)
local ok, help = pcall(require, "codediff.ui.keymap_help")
if ok and help then
help.toggle(tabpage)
else
vim.notify_once("[codediff] failed to load codediff.ui.keymap_help: " .. tostring(help), vim.log.levels.WARN)
end
end, { desc = "Show keymap help" })
end

Expand Down
20 changes: 20 additions & 0 deletions lua/codediff/ui/view/side_by_side.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ local render = require("codediff.ui.view.render")
local view_keymaps = require("codediff.ui.view.keymaps")
local conflict_window = require("codediff.ui.view.conflict_window")
local panel = require("codediff.ui.view.panel")
local welcome_window = require("codediff.ui.view.welcome_window")

local is_virtual_revision = helpers.is_virtual_revision
local prepare_buffer = helpers.prepare_buffer
Expand Down Expand Up @@ -72,6 +73,8 @@ function M.create(session_config, filetype, on_ready)
pcall(vim.api.nvim_buf_set_name, mod_scratch, "CodeDiff " .. tabpage .. ".2")
vim.api.nvim_win_set_buf(original_win, orig_scratch)
vim.api.nvim_win_set_buf(modified_win, mod_scratch)
welcome_window.sync(original_win)
welcome_window.sync(modified_win)

-- Create placeholder buffer info (will be updated by explorer)
original_info = { bufnr = orig_scratch }
Expand Down Expand Up @@ -107,6 +110,8 @@ function M.create(session_config, filetype, on_ready)
else
vim.api.nvim_win_set_buf(modified_win, modified_info.bufnr)
end
welcome_window.sync(original_win)
welcome_window.sync(modified_win)
end

-- Clean up initial buffer
Expand Down Expand Up @@ -662,6 +667,9 @@ function M.update(tabpage, session_config, auto_scroll_to_first_hunk)
end
end

welcome_window.sync(original_win)
welcome_window.sync(modified_win)

-- Update lifecycle session metadata
lifecycle.update_paths(tabpage, session_config.original_path, session_config.modified_path)

Expand Down Expand Up @@ -729,6 +737,7 @@ local function show_single_file(tabpage, opts)
-- Load the file into the kept window
if keep_win and vim.api.nvim_win_is_valid(keep_win) then
vim.api.nvim_win_set_buf(keep_win, opts.load_bufnr)
welcome_window.sync(keep_win)

-- Create a scratch buffer as placeholder for the empty side
local empty_buf = vim.api.nvim_create_buf(false, true)
Expand All @@ -747,6 +756,9 @@ local function show_single_file(tabpage, opts)
end

layout.arrange(tabpage)
if keep_win and vim.api.nvim_win_is_valid(keep_win) then
welcome_window.sync_later(keep_win)
end
end

-- Load a real file from disk, return bufnr
Expand Down Expand Up @@ -805,4 +817,12 @@ function M.show_deleted_virtual_file(tabpage, git_root, file_path, revision)
})
end

--- Show the welcome page in a single pane (modified side)
function M.show_welcome(tabpage, load_bufnr)
show_single_file(tabpage, {
keep = "modified",
load_bufnr = load_bufnr,
})
end

return M
Loading