A Neovim plugin that provides VSCode-style side-by-side diff rendering with two-tier highlighting.
https://github.com/user-attachments/assets/64c41f01-dffe-4318-bce4-16eec8de356e
Demo: Quick walkthrough of diff features
curl or wget (for automatic binary download)nui.nvim (for explorer UI)No compiler required! The plugin automatically downloads pre-built binaries from GitHub releases.
Minimal installation:
{
"esmuellert/vscode-diff.nvim",
dependencies = { "MunifTanjim/nui.nvim" },
}
Note: The plugin automatically adapts to your colorscheme's background (dark/light). It uses
DiffAddandDiffDeletefor line-level diffs, and auto-adjusts brightness for character-level highlights (1.4x brighter for dark themes, 0.92x darker for light themes). See Highlight Groups for customization.
With custom configuration:
{
"esmuellert/vscode-diff.nvim",
dependencies = { "MunifTanjim/nui.nvim" },
config = function()
require("vscode-diff").setup({
-- Highlight configuration
highlights = {
-- 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)
},
-- Keymaps in diff view
keymaps = {
view = {
next_hunk = "]c", -- Jump to next change
prev_hunk = "[c", -- Jump to previous change
next_file = "]f", -- Next file in explorer mode
prev_file = "[f", -- Previous file in explorer mode
},
explorer = {
select = "<CR>", -- Open diff for selected file
hover = "K", -- Show file diff preview
refresh = "R", -- Refresh git status
},
},
})
end,
}
The C library will be downloaded automatically on first use. No build step needed!
The plugin automatically manages the C library installation:
Automatic Updates:
Manual Installation Commands:
" Install/update the library manually
:CodeDiff install
" Force reinstall (useful for troubleshooting)
:CodeDiff install!
Version Management:
The installer reads the VERSION file to download the matching library version from GitHub releases. This ensures compatibility between the Lua code and C library.
If you prefer to install manually without a plugin manager:
git clone https://github.com/esmuellert/vscode-diff.nvim ~/.local/share/nvim/vscode-diff.nvim
init.lua:vim.opt.rtp:append("~/.local/share/nvim/vscode-diff.nvim")
The plugin requires a C library binary in the plugin root directory. The plugin auto-detects these filenames:
libvscode_diff.so or libvscode_diff_<version>.so (Linux/BSD)libvscode_diff.dylib or libvscode_diff_<version>.dylib (macOS)libvscode_diff.dll or libvscode_diff_<version>.dll (Windows)Option A: Download from GitHub releases (recommended)
Download the appropriate binary from the GitHub releases page and place it in the plugin root directory. Rename it to match the expected format: libvscode_diff.so/.dylib/.dll or libvscode_diff_<version>.so/.dylib/.dll.
Option B: Build from source
Build requirements: C compiler (GCC/Clang/MSVC/MinGW) or CMake 3.15+
Using build scripts (no CMake required):
# Linux/macOS/BSD
./build.sh
# Windows
build.cmd
Or using CMake:
cmake -B build
cmake --build build
Both methods automatically place the library in the plugin root directory.
The :CodeDiff command supports multiple modes:
Open an interactive file explorer showing changed files:
" Show git status in explorer (default)
:CodeDiff
" Show changes for specific revision in explorer
:CodeDiff HEAD~5
" Compare against a branch
:CodeDiff main
" Compare against a specific commit
:CodeDiff abc123
" Compare two revisions (e.g. HEAD vs main)
:CodeDiff main HEAD
Compare the current buffer with a git revision:
" Compare with last commit
:CodeDiff file HEAD
" Compare with previous commit
:CodeDiff file HEAD~1
" Compare with specific commit
:CodeDiff file abc123
" Compare with branch
:CodeDiff file main
" Compare with tag
:CodeDiff file v1.0.0
" Compare two revisions for current file
:CodeDiff file main HEAD
Requirements:
Behavior:
Compare two arbitrary files side-by-side:
:CodeDiff file file_a.txt file_b.txt
-- Primary user API - setup configuration
require("vscode-diff").setup({
highlights = {
line_insert = "DiffAdd",
line_delete = "DiffDelete",
char_brightness = 1.4,
},
})
-- Advanced usage - direct access to internal modules
local diff = require("vscode-diff.diff")
local render = require("vscode-diff.render")
local git = require("vscode-diff.git")
-- Example 1: Compute diff between two sets of lines
local lines_a = {"line 1", "line 2"}
local lines_b = {"line 1", "modified line 2"}
local lines_diff = diff.compute_diff(lines_a, lines_b)
-- Example 2: Get file content from git (async)
git.get_file_content("HEAD~1", "/path/to/repo", "relative/path.lua", function(err, lines)
if err then
vim.notify(err, vim.log.levels.ERROR)
return
end
-- Use lines...
end)
-- Example 3: Get git root for a file (async)
git.get_git_root("/path/to/file.lua", function(err, git_root)
if not err then
-- File is in a git repository
end
end)
C Module (libvscode-diff/): Fast diff computation and render plan generation
rangeMapping.ts data structuresLua FFI Layer (lua/vscode-diff/diff.lua): Bridge between C and Lua
Render Module (lua/vscode-diff/render/): Neovim buffer rendering
The plugin handles syntax highlighting differently based on buffer type:
Working files (editable):
Git history files (read-only):
The plugin defines highlight groups matching VSCode's diff colors:
CodeDiffLineInsert - Light green background for inserted linesCodeDiffLineDelete - Light red background for deleted linesCodeDiffCharInsert - Deep/dark green for inserted charactersCodeDiffCharDelete - Deep/dark red for deleted charactersCodeDiffFiller - Gray foreground for filler line slashes (╱╱╱)Dawnfox Light - Default configuration with auto-detected brightness (char_brightness = 0.92 for light themes):
Catppuccin Mocha - Default configuration with auto-detected brightness (char_brightness = 1.4 for dark themes):
Kanagawa Lotus - Default configuration with auto-detected brightness (char_brightness = 0.92 for light themes):
Default behavior:
DiffAdd and DiffDelete for line-level highlightsvim.o.background:background = "dark"): Brightness multiplied by 1.4 (40% brighter)background = "light"): Brightness multiplied by 0.92 (8% darker)char_brightness value if neededCustomization examples:
-- Use hex colors directly
highlights = {
line_insert = "#1d3042",
line_delete = "#351d2b",
char_brightness = 1.5, -- Override auto-detection with explicit value
}
-- Override character colors explicitly
highlights = {
line_insert = "DiffAdd",
line_delete = "DiffDelete",
char_insert = "#3fb950",
char_delete = "#ff7b72",
}
-- Mix highlight groups and hex colors
highlights = {
line_insert = "String",
char_delete = "#ff0000",
}
make clean && make
Run all tests:
make test # Run all tests (C + Lua integration)
Run specific test suites:
make test-c # C unit tests only
make test-lua # Lua integration tests only
For more details on the test structure, see tests/README.md.
vscode-diff.nvim/
├── libvscode-diff/ # C diff engine
│ ├── src/ # C implementation
│ ├── include/ # C headers
│ └── tests/ # C unit tests
├── lua/vscode-diff/ # Lua modules
│ ├── init.lua # Main API
│ ├── config.lua # Configuration
│ ├── diff.lua # FFI interface
│ ├── git.lua # Git operations
│ ├── commands.lua # Command handlers
│ ├── installer.lua # Binary installer
│ └── render/ # Rendering modules
│ ├── core.lua # Diff rendering
│ ├── view.lua # View management
│ ├── explorer.lua # Git status explorer
│ └── highlights.lua # Highlight setup
├── plugin/ # Plugin entry point
│ └── vscode-diff.lua # Auto-loaded on startup
├── tests/ # Test suite (plenary.nvim)
│ └── README.md # Test documentation
├── docs/ # Production docs
├── dev-docs/ # Development docs
├── Makefile # Build automation
└── README.md # This file
This plugin follows VSCode's diff rendering architecture:
src/vs/editor/common/diff/rangeMapping.tssrc/vs/editor/browser/widget/diffEditor/registrations.contribution.tssrc/vs/editor/browser/widget/diffEditor/style.cssMIT
Contributions are welcome! Please ensure:
make test)