Conversation
Add --no-show-signature flag to git log and show commands to prevent GPG signature output from interfering with parsing. This fixes issues when users have log.showSignature enabled in their git config. Fixes sindrets#537
Only expand environment variables in paths when the variable is actually defined. Previously, undefined variables would be replaced with their literal name (e.g., $FOO -> FOO), which could cause unexpected behaviour with paths containing dollar signs. Fixes sindrets#556
) Show untracked files when the right side of the comparison is the working tree (LOCAL), not just when comparing index vs working tree. This allows seeing untracked files in more diff scenarios. Fixes sindrets#584
When running `git rebase -i --root`, the initial commit has no parent, so `git merge-base` fails. Instead of crashing with an assertion error, gracefully handle this by using the empty tree SHA as the base. Fixes sindrets#576
Add support for mini.icons as an alternative to nvim-web-devicons for file icons. The plugin will try nvim-web-devicons first, then fall back to mini.icons if available.
Add q and <esc> keymaps to close the commit log panel, matching the behaviour of other panels like the help panel. The keymaps are configurable via keymaps.commit_log_panel. Fixes sindrets#481
…drets#606) Use the unnamed register (") instead of the system clipboard (+) when copying commit hashes. This is more consistent with Vim conventions and works regardless of clipboard support. Fixes sindrets#604
Add nil check for comp.context before accessing mapping property. Pressing <CR> on the first line of the help panel no longer errors. Fixes sindrets#469
Requiring diffview.lib directly without going through diffview.bootstrap would fail with "attempt to index global 'DiffviewGlobal' (a nil value)". Now lib.lua explicitly requires bootstrap to ensure initialisation. Fixes sindrets#511
Some colorschemes don't define diffAdded/diffRemoved/diffChanged until the diff filetype is encountered. Now we explicitly load the diff syntax file if these highlight groups don't exist, ensuring our highlight links work correctly. Fixes sindrets#351
Makes it more visually clear which items are directories, especially when not using folder icons. Closes sindrets#247
Users can now set `file_panel.show = false` to have the file panel hidden by default when opening Diffview. The panel can still be toggled using the toggle_files action. Closes sindrets#303
When multiple git operations run concurrently (e.g., staging files while other plugins like nvim-tree also make git calls), lock contention can cause significant slowdowns. Setting GIT_OPTIONAL_LOCKS=0 tells git to skip optional locking, improving performance. Fixes sindrets#535
Allows users to bind keys to specific layouts directly instead of cycling through all layouts.
The explicit definition with a "White" fallback caused invisible filenames on light colorschemes. FilePanelFileName is already linked to Normal in hl_links, which correctly inherits the theme's text color.
Use consistent highlighting for fold indicators across all views. Previously FileHistory used CursorLineNr which didn't match the rest of the UI.
Allow users to configure the maximum length for commit subject display in the file history panel. Defaults to 72 characters.
Added "Recommended Keymaps" section with common patterns: - Toggle diffview open/close - File/line/range history - Diff against main/master branch Added tips for merge-base comparisons, Neogit integration, and line evolution tracing.
Display a friendly message in the file panel when there are no changes to show instead of just an empty section.
Added view.cycle_layouts config with default and merge_tool presets to allow users to specify which layouts to cycle through. Resolves sindrets#336
Added section showing how to use Telescope for branch and commit selection when opening diffview. Resolves sindrets#279
When enabled, Changes and Staged changes sections are always shown in the file panel even when empty. Resolves sindrets#478
Uses xdg-open on Linux, open on macOS, and start on Windows. Default keymap is 'gx' matching vim's convention. Resolves sindrets#456
…ry (sindrets#569) Adds a new action diff_against_head that opens a diffview comparing HEAD with the commit under cursor in the file history panel. Bound to 'H' by default.
Save and restore the collapsed state of directory nodes when file trees are recreated. This prevents folders from expanding when switching tabs.
…ets#330) - Use window-local options (vim.wo) instead of global options (vim.o) when saving window options before opening a diff - Add explicit winopts to NULL_FILE to disable diff-related settings (scrollbind, cursorbind, etc.) preventing option cascading
- Set foldlevel=99 to keep folds open by default, preventing issues with plugins like vim-markdown that create section folds - Add explicit jump to first diff hunk when opening files, since the previous behaviour of showing the first diff was a side effect of foldlevel=0 folding away unchanged lines - Add Plugin Compatibility section to README
Diagnostics only work for working tree (LOCAL) buffers because LSP servers don't attach to non-file buffers (buftype=nowrite). When comparing commits like `main..HEAD`, users should use `DiffviewOpen main` to see diagnostics on the working tree side.
The default keymaps (<leader>e, <leader>b, <leader>c*) may conflict with user configurations. Rather than changing defaults (breaking change), document how to override them with localleader or disable them entirely.
Remove trailing periods from two keymap descriptions for consistency. All descriptions now use sentence fragments without trailing periods. Also document technical debt in OPEN_ISSUES.md: - Deprecated nvim_buf_set_option/get_option API calls - FIXME comments for null handling and Mercurial limitations
PR sindrets#587 changed the condition to show untracked files whenever the right side is LOCAL (working tree). This caused untracked files to appear when running `DiffviewOpen <commit>`, which compares a commit to the working tree. Restore the original behaviour: only show untracked files when comparing STAGE (index) vs LOCAL (working tree), i.e. standard `DiffviewOpen`.
* refactor: bump minimum Neovim version to 0.10 * fix(layouts): implement proper should_null for Diff1 * fix(api): use left_null/right_null in CDiffView * feat(sindrets#485): add pushed/unpushed commit colour distinction in file history * feat(sindrets#207): add configurable diffopt overrides
…ions (#12) Restructure Plugin Compatibility into Companion Plugins with Recommended and Known Issues subsections. Add links to all external plugins at first mention. Add character-level highlighting tip pointing to diffchar.vim.
…hting for deletions (#13)
There was a problem hiding this comment.
Pull request overview
This PR ports the v0.10 changes from the dlyongemallo/diffview.nvim fork back into this codebase, including a Neovim 0.10+ baseline, multiple UX/features (toggle command, new actions, more config), and a broad set of stability/performance fixes across DiffView/FileHistory/UI/VCS layers.
Changes:
- Add new commands/actions/config options (e.g.,
:DiffviewToggle, merge-base support, browser/file external open, layout cycling config, status icons, panel UX tweaks). - Improve robustness and UX in views/panels (loading indicator, cursor restoration, fold/keymap save/restore, async race guards, null buffer handling).
- Raise minimum Neovim requirement to 0.10 and modernize APIs (
vim.uv,vim.bo,vim.health,nvim_get_option_info2, etc.), plus docs/test updates.
Reviewed changes
Copilot reviewed 46 out of 46 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| plugin/diffview.lua | Adds :DiffviewToggle command wiring. |
| lua/diffview/vcs/utils.lua | Adds merge-artifact filtering utilities + applies filtering to diff file lists. |
| lua/diffview/vcs/log_entry.lua | Adds has_remote_ref metadata for commit formatting/HL decisions. |
| lua/diffview/vcs/file_dict.lua | Preserves/restores file-tree collapsed state across updates. |
| lua/diffview/vcs/file.lua | Updates buffer/window opts (foldlevel/winhl prepend), switches to vim.bo, tracks created bufs, keymap save/restore, diagnostics/inlay-hint handling. |
| lua/diffview/vcs/adapters/hg/init.lua | Switches to vim.uv, adds selected-row, adds branch/default-branch helpers. |
| lua/diffview/vcs/adapters/git/init.lua | Switches to vim.uv, adds --no-show-signature, merge-base option, rename threshold flags, branch/default branch + remote/commit URL helpers, selected-row. |
| lua/diffview/utils.lua | Switches time to vim.uv, uses nvim_get_option_info2, adds vec_extend, assumes vim.islist. |
| lua/diffview/ui/panels/help_panel.lua | Fixes nil-index crash when applying help-panel commands. |
| lua/diffview/ui/panels/commit_log_panel.lua | Refactors init signature, closes panel on parent close, registers keymaps in init_buffer(). |
| lua/diffview/ui/panel.lua | Adds position="auto" support and switches buf option setting to vim.bo. |
| lua/diffview/ui/models/file_tree/node.lua | Adds custom file sorting comparator hook for file panel. |
| lua/diffview/ui/models/file_tree/file_tree.lua | Stores node backref and adds get/set collapsed-state helpers. |
| lua/diffview/tests/functional/pathlib_spec.lua | Updates env-var expansion expectations. |
| lua/diffview/scene/window.lua | Context-plugin disable/restore, winopt save fixes for global-only opts, custom fold cap + safer fold creation. |
| lua/diffview/scene/views/standard/standard_view.lua | Honors file_panel.show by focusing main view when panel hidden. |
| lua/diffview/scene/views/file_history/render.lua | Adds stat bar rendering + configurable commit entry formatting and date/subject styling. |
| lua/diffview/scene/views/file_history/listeners.lua | Adds cursor restore, “diff against HEAD”, intra-commit cycling, unnamed-register hash copy, open-commit-in-browser. |
| lua/diffview/scene/views/file_history/file_history_view.lua | Updates commit-log panel construction and adds created-buffer cleanup on close. |
| lua/diffview/scene/views/diff/render.lua | Uses status icons, always shows folder icons + trailing slash + collapsed counts, branch display, loading + empty/clean messages, always-show sections option. |
| lua/diffview/scene/views/diff/listeners.lua | Cursor restore, auto-close-on-empty, improved initial navigation, directory restore support, untracked toggle action. |
| lua/diffview/scene/views/diff/file_panel.lua | Introduces is_loading state. |
| lua/diffview/scene/views/diff/diff_view.lua | Adds selected_row, loading state handling, created-buffer cleanup, async race/cancel guards + nil guards. |
| lua/diffview/scene/view.lua | Adds diffopt override/apply/restore behavior scoped to Diffview tabs. |
| lua/diffview/scene/layouts/diff_1.lua | Implements should_null logic for diff1 layout. |
| lua/diffview/scene/layout.lua | Opens null buffers early to prevent flash; guards sync_scroll nil target. |
| lua/diffview/renderer.lua | Switches timing to vim.uv and buffer option access to vim.bo. |
| lua/diffview/perf.lua | Switches to vim.uv. |
| lua/diffview/path.lua | Switches to vim.uv; adjusts env-var expansion semantics. |
| lua/diffview/logger.lua | Switches to vim.uv. |
| lua/diffview/lib.lua | Ensures bootstrap runs; adds “find existing view” behavior. |
| lua/diffview/job.lua | Switches to vim.uv; sets GIT_OPTIONAL_LOCKS=0 by default in job env. |
| lua/diffview/init.lua | Adds toggle() API; uses vec_extend in completion candidates. |
| lua/diffview/hl.lua | Adds mini.icons support, status icon mapping, diff syntax load ordering, removes legacy-version branches. |
| lua/diffview/health.lua | Requires Neovim 0.10+, adds mini.icons as optional dep. |
| lua/diffview/ffi.lua | Simplifies locking checks for newer Neovim/LuaJIT assumptions. |
| lua/diffview/debounce.lua | Schedules timer callbacks via vim.schedule to avoid fast-event API errors. |
| lua/diffview/config.lua | Adds many new config options + keymaps, including cycle_layouts and status_icons. |
| lua/diffview/bootstrap.lua | Enforces Neovim 0.10+ minimum and uses vim.uv. |
| lua/diffview/async.lua | Switches to vim.uv. |
| lua/diffview/api/views/diff/diff_view.lua | Improves null-buffer selection per-side; integrates layout should_null fallback. |
| lua/diffview/actions.lua | Adds external open/new-tab/default-branch diff actions; configurable layout cycling + set_layout; adds new action names. |
| doc/diffview_defaults.txt | Updates documented defaults (icons providers, new options). |
| doc/diffview.txt | Documents :DiffviewToggle. |
| README.md | Updates requirements/docs and adds new usage sections and integrations/tips. |
| .github/ISSUE_TEMPLATE/bug_report.yml | Updates minimal repro template colorscheme selection. |
Comments suppressed due to low confidence (2)
lua/diffview/init.lua:170
:DiffviewToggleuses the same completion function as:DiffviewOpen, butdiffview.completion()only has completers forDiffviewOpenandDiffviewFileHistory. As a result, command-line completion for:DiffviewTogglewon’t work. Consider adding aDiffviewTogglecompleter (e.g., alias it toDiffviewOpen) or mappingDiffviewToggletoDiffviewOpeninsideM.completion().
function M.completion(_, cmd_line, cur_pos)
local ctx = arg_parser.scan(cmd_line, { cur_pos = cur_pos, allow_ex_range = true })
local cmd = ctx.args[1]
if cmd and M.completers[cmd] then
return arg_parser.process_candidates(M.completers[cmd](ctx), ctx)
end
end
README.md:4
- The README now states this repository is a fork of
sindrets/diffview.nvim, but the PR description says these fork changes are being brought back into the original repo. If this repo is the upstream/original, this note should be removed or rewritten to avoid confusing users.
Single tabpage interface for easily cycling through diffs for all modified files
for any git rev.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if err then | ||
| utils.err("Failed to update files in a diff view!", true) | ||
| logger:error("[DiffView] Failed to update files!") | ||
| callback(err) | ||
| return | ||
| end |
There was a problem hiding this comment.
When get_updated_files() returns an error, panel.is_loading / self.is_loading are never cleared. This can leave the file panel stuck showing the loading message (Fetching changes...) until a successful refresh. Consider clearing the loading flags (and re-rendering) in the error/early-return paths as well.
| if item then | ||
| vim.fn.setreg("+", item.commit.hash) | ||
| vim.fn.setreg('"', item.commit.hash) | ||
| utils.info(string.format("Copied '%s' to the clipboard.", item.commit.hash)) |
There was a problem hiding this comment.
This message says the hash was copied to the clipboard, but the code now writes to the unnamed register ("). Update the message to reflect the actual target register (or copy to +/* if you intend clipboard behavior).
| utils.info(string.format("Copied '%s' to the clipboard.", item.commit.hash)) | |
| utils.info(string.format("Copied '%s' to the default register.", item.commit.hash)) |
| elseif vim.fn.has("unix") == 1 then | ||
| cmd = { "xdg-open", url } | ||
| elseif vim.fn.has("win32") == 1 then | ||
| cmd = { "cmd", "/c", "start", '""', url } |
There was a problem hiding this comment.
On Windows, cmd /c start expects an empty title argument as "" at the command-line level; when passing argv via jobstart(), providing the literal string '""' may not behave as intended. Consider using an actual empty string (as in actions.open_file_external) for consistency, or otherwise ensure the argument is correctly translated to an empty title.
| cmd = { "cmd", "/c", "start", '""', url } | |
| cmd = { "cmd", "/c", "start", "", url } |
| -- Use config or fall back to defaults. | ||
| local layout_cycles = { | ||
| standard = { | ||
| Diff2Hor.__get(), | ||
| Diff2Ver.__get(), | ||
| }, | ||
| merge_tool = { | ||
| Diff3Hor.__get(), | ||
| Diff3Ver.__get(), | ||
| Diff3Mixed.__get(), | ||
| Diff4Mixed.__get(), | ||
| Diff1.__get(), | ||
| } | ||
| standard = #(cycle_config.default or {}) > 0 | ||
| and resolve_layouts(cycle_config.default) | ||
| or { Diff2Hor.__get(), Diff2Ver.__get() }, | ||
| merge_tool = #(cycle_config.merge_tool or {}) > 0 | ||
| and resolve_layouts(cycle_config.merge_tool) | ||
| or { Diff3Hor.__get(), Diff3Ver.__get(), Diff3Mixed.__get(), Diff4Mixed.__get(), Diff1.__get() }, | ||
| } |
There was a problem hiding this comment.
If conf.view.cycle_layouts.* contains only unknown layout names, resolve_layouts() can return an empty list, and the later % #layouts computation will raise a division-by-zero error. Consider falling back to the default cycle list when the resolved list is empty (or validate cycle_layouts entries during config setup).
Summary
This PR brings the changes from the dlyongemallo/diffview.nvim fork (v0.10 release) back to the original repo. See #605 for context.
Highlights
Bug fixes (24):
logcommands #540)winhl), not set (winblend) #515)New features (30):
:DiffviewTogglecommand (feat: AddDiffviewTogglecommand #517)--merge-baseoption (feat: enable merge-base option when compare working tree with specific ref #590)--selected-rowoption for cursor positioningXrestore.entry to restore whole directory #186)DiffviewOpendoesn't recognizesplitrightoption #536)Performance:
Breaking:
Docs:
Test plan
make testto verify existing tests pass:DiffviewOpen,:DiffviewFileHistory,:DiffviewTogglecommands