Skip to content

Conversation

@dlyongemallo
Copy link

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):

New features (30):

Performance:

  • Set GIT_OPTIONAL_LOCKS=0 to reduce lock contention

Breaking:

  • Bump minimum required Neovim version to 0.10
  • Replace deprecated nvim_buf_get/set_option with vim.bo

Docs:

  • Add DiffviewToggle docs, diffopt tips, Telescope integration examples, keymaps FAQ, treesitter-context setup, recommended keymaps, diffchar.vim recommendation

Test plan

  • Run make test to verify existing tests pass
  • Test :DiffviewOpen, :DiffviewFileHistory, :DiffviewToggle commands
  • Verify merge conflict resolution in 3-way/4-way layouts
  • Test with Neovim 0.10+

Naxdy and others added 30 commits November 1, 2025 10:15
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
dlyongemallo and others added 25 commits February 4, 2026 11:34
- 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`.
…d of init (#1)

Fixes bug introduced in 1b386ce which caused Esc to close any diffview window.
* 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.
Copilot AI review requested due to automatic review settings February 12, 2026 12:39
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  • :DiffviewToggle uses the same completion function as :DiffviewOpen, but diffview.completion() only has completers for DiffviewOpen and DiffviewFileHistory. As a result, command-line completion for :DiffviewToggle won’t work. Consider adding a DiffviewToggle completer (e.g., alias it to DiffviewOpen) or mapping DiffviewToggle to DiffviewOpen inside M.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.

Comment on lines 389 to 394
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
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
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))
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
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))

Copilot uses AI. Check for mistakes.
elseif vim.fn.has("unix") == 1 then
cmd = { "xdg-open", url }
elseif vim.fn.has("win32") == 1 then
cmd = { "cmd", "/c", "start", '""', url }
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
cmd = { "cmd", "/c", "start", '""', url }
cmd = { "cmd", "/c", "start", "", url }

Copilot uses AI. Check for mistakes.
Comment on lines +604 to 612
-- 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() },
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.