DiffBandit is a Neovim diff viewer with independent panes, compact connector geometry, Git-aware navigation, hunk actions, a commit panel, binary hex diffs, and theme-adaptive highlights.
It is designed to feel like a focused editor-native diff tool: source buffers keep natural scrolling, line numbers stay docked to their side, and the middle gutter shows the relationship between changed regions without repeating source content.
- Three-part diff layout with left content, connector gutter, and right content.
- Independent source scrolling with synchronized line-number panes.
- Connector routes for additions, deletions, changes, mixed hunks, and scroll-clipped regions.
- Git queue navigation for changed files with
]fand[f. - Hunk staging, unstaging, discard/apply actions, and undo.
- Optional Git commit panel with file staging, amend mode, commit message entry, and live diff preview.
- One-column overview gutters that show changed regions proportionally across each document.
- Binary file support through a read-only hex comparison view.
- Theme-friendly semantic colors derived from the active colorscheme, with optional overrides.
- Plain Unicode defaults with optional Nerd Font-style icon overrides.
- Neovim 0.10 or newer.
- Git for
:DiffBanditGit,:DiffBanditGitCurrent, hunk actions, and the commit panel. - tmux only for running the integration test suite.
- Nerd Fonts are optional.
With lazy.nvim:
{
"CoreyKaylor/diffbandit.nvim",
config = function()
require("diffbandit").setup()
end,
}Compare two files:
:DiffBandit path/to/left path/to/rightCompare two loaded buffers by buffer number:
:DiffBanditBuffers 3 7Open the current repository's changed files:
:DiffBanditGitOpen the current file as a Git diff:
:DiffBanditGitCurrentToggle the Git commit panel:
:DiffBanditCommitPanel:DiffBanditGit accepts common diff scopes:
:DiffBanditGit " all changes, including staged and unstaged
:DiffBanditGit --staged " staged changes only
:DiffBanditGit --cached " alias for --staged
:DiffBanditGit --all " staged and unstaged changes
:DiffBanditGit --current " current file scope
:DiffBanditGit --base main " compare against a base revision
:DiffBanditGit --rev main..HEAD
:DiffBanditGit --no-untracked
:DiffBanditGit -- -- pathspecBy default, Git diffs use all mode and include untracked files.
Inside a diff view:
| Key | Action |
|---|---|
]c |
Next hunk |
[c |
Previous hunk |
]f |
Next changed file in a Git queue |
[f |
Previous changed file in a Git queue |
[d |
Align both panes to the top of the documents |
]d |
Align both panes to the bottom of the documents |
C |
Open or focus the commit panel for the current Git file |
<Space> |
Toggle stage for the active Git hunk |
>> |
Apply the left side to the right target |
<< |
Apply the right side to the left target |
u |
Undo the last DiffBandit hunk action |
q |
Close the diff session |
At a file boundary, ]c and [c first notify that the next press will move to
the next or previous file. This keeps hunk navigation deliberate while still
making multi-file Git review quick.
Open the panel with :DiffBanditCommitPanel, or press C from a Git diff
opened by :DiffBanditGit.
| Key | Action |
|---|---|
j / k |
Move through changed files and preview the selected file |
<CR> |
Focus the diff for the selected file |
]c / [c |
Navigate hunks in the selected file preview |
<Space> |
Toggle staged state for the selected file |
cc |
Focus the commit message window |
<Space> in the commit message window |
Toggle amend mode |
:w in the commit message window |
Commit staged changes |
R |
Refresh the panel |
q |
Close the panel |
The panel validates empty commit messages and missing staged changes before committing. In amend mode, the panel compares against the previous commit so the file state reflects what the amended commit would contain.
Git hunk actions operate on the active hunk in the right-side document pane:
<Space>stages an unstaged hunk or unstages an already staged hunk inallmode.>>applies the left side of the hunk to the right target.<<applies the right side of the hunk to the left target.uundoes DiffBandit apply/stage actions in reverse order for the current file.
Staged hunks show an indicator next to the right-side line numbers. The default symbols are plain Unicode squares so the UI remains usable without a patched font.
Binary files render as a read-only hex diff by default. Configure the hex view with:
require("diffbandit").setup({
ui = {
hex = {
enabled = true,
bytes_per_row = 16,
max_bytes = 65536,
show_ascii = true,
show_offsets = true,
},
},
})Set ui.hex.enabled = false to show a compact binary-file notice instead.
Default setup:
require("diffbandit").setup()Example with common customizations:
require("diffbandit").setup({
diff = {
algorithm = "myers",
linematch = 60,
ignore_whitespace = false,
},
navigation = {
initial_focus = "right",
align_on_jump = true,
align_strategy = "change_top",
document_keys = {
top = "[d",
bottom = "]d",
},
},
git = {
default_mode = "all",
include_untracked = true,
find_renames = true,
file_keys = {
next = "]f",
prev = "[f",
},
panel = {
width = 42,
commit_height = 10,
preview_on_cursor = true,
keys = {
toggle_stage = "<Space>",
focus_diff = "<CR>",
focus_panel = "C",
focus_commit = "cc",
toggle_amend = "<Space>",
refresh = "R",
close = "q",
},
},
},
ui = {
connector_width = 12,
scroll_debounce_ms = 16,
split_blend = 0.3,
overview = {
enabled = true,
width = 1,
cursor = true,
},
status = {
enabled = true,
icons = "auto",
},
theme = {
auto_refresh = true,
semantic_blend = 0.3,
change_emphasis_strength = 0.16,
min_background_delta = 0.08,
colors = {
add = nil,
delete = nil,
change = nil,
change_emphasis = nil,
},
highlights = {},
},
},
actions = {
staged_indicator = {
unstaged = "□",
staged = "▣",
},
},
})Theme colors are derived from the active colorscheme's diff highlight groups.
Use ui.theme.colors for semantic color overrides, or ui.theme.highlights to
override specific DiffBandit* highlight groups.
local diffbandit = require("diffbandit")
diffbandit.setup({})
diffbandit.files("left.txt", "right.txt")
diffbandit.buffers(left_bufnr, right_bufnr)
diffbandit.git({ mode = "all" })
diffbandit.git_file(nil, { mode = "all" })
diffbandit.commit_panel({})Hunk actions are also exposed as Lua functions:
diffbandit.toggle_stage_hunk()
diffbandit.stage_hunk()
diffbandit.unstage_hunk()
diffbandit.discard_hunk()
diffbandit.apply_left_hunk()
diffbandit.apply_right_hunk()
diffbandit.undo()Run the unit/spec suite:
nvim --headless -u tests/run.luaRun the tmux integration suite:
tests/integration/run.shThe integration tests capture terminal output, including ANSI highlights, so they can verify connector geometry, backgrounds, underline spans, Git actions, commit panel behavior, binary diffs, and scrolling behavior.
diffbandit.nvim is licensed under the Apache License, Version 2.0. See
LICENSE.








