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
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,23 +68,30 @@ https://github.com/user-attachments/assets/64c41f01-dffe-4318-bce4-16eec8de356e
-- Line-level: accepts highlight group names or hex colors (e.g., "#2ea043")
line_insert = "DiffAdd", -- Line-level insertions
line_delete = "DiffDelete", -- Line-level deletions

-- Character-level: accepts highlight group names or hex colors
-- If specified, these override char_brightness calculation
char_insert = nil, -- Character-level insertions (nil = auto-derive)
char_delete = nil, -- Character-level deletions (nil = auto-derive)

-- Brightness multiplier (only used when char_insert/char_delete are nil)
-- nil = auto-detect based on background (1.4 for dark, 0.92 for light)
char_brightness = nil, -- Auto-adjust based on your colorscheme
},

-- Diff view behavior
diff = {
disable_inlay_hints = true, -- Disable inlay hints in diff windows for cleaner view
max_computation_time_ms = 5000, -- Maximum time for diff computation (VSCode default)
},


-- Explorer panel configuration
explorer = {
position = "left", -- "left" or "bottom"
width = 40, -- Width when position is "left" (columns)
height = 15, -- Height when position is "bottom" (lines)
},

-- Keymaps in diff view
keymaps = {
view = {
Expand All @@ -94,6 +101,8 @@ https://github.com/user-attachments/assets/64c41f01-dffe-4318-bce4-16eec8de356e
prev_hunk = "[c", -- Jump to previous change
next_file = "]f", -- Next file in explorer mode
prev_file = "[f", -- Previous file in explorer mode
diff_get = "do", -- Get change from other buffer (like vimdiff)
diff_put = "dp", -- Put change to other buffer (like vimdiff)
},
explorer = {
select = "<CR>", -- Open diff for selected file
Expand Down
7 changes: 7 additions & 0 deletions lua/vscode-diff/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ M.defaults = {
max_computation_time_ms = 5000, -- Maximum time for diff computation (5 seconds, VSCode default)
},

-- Explorer panel configuration
explorer = {
position = "left", -- "left" or "bottom"
width = 40, -- Width when position is "left" (columns)
height = 15, -- Height when position is "bottom" (lines)
},

-- Keymaps
keymaps = {
view = {
Expand Down
54 changes: 33 additions & 21 deletions lua/vscode-diff/render/explorer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -97,39 +97,38 @@ local function prepare_node(node, max_width, selected_path, selected_group)
-- File entry - VSCode style: filename (bold) + directory (dimmed) + status (right-aligned)
local indent = string.rep(" ", node:get_depth() - 1)
line:append(indent, get_hl("Normal"))

local icon_part = ""
if data.icon then
icon_part = data.icon .. " "
line:append(icon_part, get_hl(data.icon_color))
end

-- Status symbol at the end (e.g., "M", "D", "??")
local status_symbol = data.status_symbol or ""

-- Split path into filename and directory
local full_path = data.path or node.text
local filename = full_path:match("([^/]+)$") or full_path
local directory = full_path:sub(1, -(#filename + 1)) -- Remove filename, keep trailing /

-- Calculate how much width we've used and reserve for status
local used_width = vim.fn.strdisplaywidth(indent) + vim.fn.strdisplaywidth(icon_part)
local status_reserve = vim.fn.strdisplaywidth(status_symbol) + 2 -- 2 spaces padding before status
local available_for_content = max_width - used_width - status_reserve
-- VSCode shows: filename + directory (dimmed), truncate directory if needed

-- Show: filename + full directory path, truncate directory from left if needed
local filename_len = vim.fn.strdisplaywidth(filename)
local directory_len = vim.fn.strdisplaywidth(directory)
local space_len = (directory_len > 0) and 1 or 0 -- Account for space between filename and directory
local space_len = (directory_len > 0) and 1 or 0

if filename_len + space_len + directory_len > available_for_content then
-- Prioritize showing full filename, truncate directory from end (right)
-- Truncate directory from the right (keep the start)
local available_for_dir = available_for_content - filename_len - space_len
if available_for_dir > 3 then
-- Show truncated directory (from the start, hide the end)
local ellipsis = "..."
local chars_to_keep = available_for_dir - vim.fn.strdisplaywidth(ellipsis)

-- Truncate directory by display width, not byte index
local byte_pos = 0
local accumulated_width = 0
Expand All @@ -146,14 +145,14 @@ local function prepare_node(node, max_width, selected_path, selected_group)
space_len = 0
end
end
-- Append filename (normal weight) and directory (dimmed with smaller font)

-- Append filename (normal weight) and directory (dimmed)
line:append(filename, get_hl("Normal"))
if #directory > 0 then
line:append(" ", get_hl("Normal"))
line:append(directory, get_hl("ExplorerDirectorySmall")) -- Smaller dimmed style
line:append(directory, get_hl("ExplorerDirectorySmall"))
end

-- Add padding to push status symbol to the right edge
local content_len = vim.fn.strdisplaywidth(filename) + space_len + vim.fn.strdisplaywidth(directory)
local padding_needed = available_for_content - content_len + 2
Expand All @@ -168,14 +167,27 @@ end

-- Create and show explorer
function M.create(status_result, git_root, tabpage, width, base_revision, target_revision)
-- Use provided width or default to 40 columns (same as neo-tree)
local explorer_width = width or 40

-- Get explorer position and size from config
local explorer_config = config.options.explorer or {}
local position = explorer_config.position or "left"
local size
local text_width -- Width for text rendering (always horizontal width)

if position == "bottom" then
size = explorer_config.height or 15
-- For bottom position, use full window width for text
text_width = vim.o.columns
else
-- Use provided width or config width or default to 40 columns
size = width or explorer_config.width or 40
text_width = size
end

-- Create split window for explorer
local split = Split({
relative = "editor",
position = "left",
size = explorer_width,
position = position,
size = size,
buf_options = {
modifiable = false,
readonly = true,
Expand Down Expand Up @@ -204,7 +216,7 @@ function M.create(status_result, git_root, tabpage, width, base_revision, target
bufnr = split.bufnr,
nodes = tree_data,
prepare_node = function(node)
return prepare_node(node, explorer_width, selected_path, selected_group)
return prepare_node(node, text_width, selected_path, selected_group)
end,
})

Expand Down
40 changes: 24 additions & 16 deletions lua/vscode-diff/render/view.lua
Original file line number Diff line number Diff line change
Expand Up @@ -653,27 +653,35 @@ function M.create(session_config, filetype)

-- For explorer mode, create the explorer sidebar after diff windows are set up
if session_config.mode == "explorer" and session_config.explorer_data then
-- Calculate explorer width: 20% of terminal width or 40 columns, whichever is smaller (matches neo-tree default)
local total_width = vim.o.columns
local explorer_width = math.min(40, math.floor(total_width * 0.2))
-- Create explorer in left sidebar (explorer manages its own lifecycle and callbacks)
-- Get explorer position from config
local explorer_config = config.options.explorer or {}
local position = explorer_config.position or "left"

-- Create explorer (explorer manages its own lifecycle and callbacks)
local explorer = require('vscode-diff.render.explorer')
local status_result = session_config.explorer_data.status_result
local explorer_obj = explorer.create(status_result, session_config.git_root, tabpage, explorer_width, session_config.original_revision, session_config.modified_revision)

local explorer_obj = explorer.create(status_result, session_config.git_root, tabpage, nil, session_config.original_revision, session_config.modified_revision)

-- Store explorer reference in lifecycle
lifecycle.set_explorer(tabpage, explorer_obj)

-- Note: Keymaps will be set when first file is selected via update()

-- After explorer is created, adjust diff window widths to be equal
local remaining_width = total_width - explorer_width
local diff_width = math.floor(remaining_width / 2)

vim.api.nvim_win_set_width(original_win, diff_width)
vim.api.nvim_win_set_width(modified_win, diff_width)

-- Adjust diff window sizes based on explorer position
if position == "bottom" then
-- For bottom position, diff windows take full width, equalize them
vim.cmd('wincmd =')
else
-- For left position, calculate remaining width and split equally
local total_width = vim.o.columns
local explorer_width = explorer_config.width or 40
local remaining_width = total_width - explorer_width
local diff_width = math.floor(remaining_width / 2)

vim.api.nvim_win_set_width(original_win, diff_width)
vim.api.nvim_win_set_width(modified_win, diff_width)
end
end

return {
Expand Down