Codediff.nvim
A Neovim plugin that provides VSCode-style diff rendering with two-tier highlighting (line + character level) in side-by-side and inline layouts, using VSCode's algorithm implemented in C.
Install / Use
/learn @esmuellert/Codediff.nvimQuality Score
Category
Development & EngineeringSupported Platforms
README
codediff.nvim
A Neovim plugin that provides VSCode-style diff rendering with two-tier highlighting, supporting both side-by-side and inline (unified) layouts.
<div align="center">https://github.com/user-attachments/assets/64c41f01-dffe-4318-bce4-16eec8de356e
Demo: Quick walkthrough of diff features
</div>Features
- Two-tier highlighting system:
- Light backgrounds for entire modified lines (green for insertions, red for deletions)
- Deep/dark character-level highlights showing exact changes within lines
- Side-by-side diff view in a new tab with synchronized scrolling
- Inline (unified) diff view — single-window layout with deleted lines as virtual overlays, with treesitter syntax highlighting
- Toggle layout — switch between side-by-side and inline layout at runtime with
t - Git integration: Compare between any git revision (HEAD, commits, branches, tags)
- Same implementation as VSCode's diff engine, providing identical visual highlighting for most scenarios
- Fast C-based diff computation using FFI with multi-core parallelization (OpenMP)
- Async git operations - non-blocking file retrieval from git
- Moved code detection — identifies blocks of code that moved within a file, with visual indicators (highlights, signs, annotations) matching VSCode's experimental
showMovesfeature (opt-in)
Installation
Prerequisites
- Neovim >= 0.7.0 (for Lua FFI support; 0.10+ recommended for vim.system)
- Git (for git diff features)
curlorwget(for automatic binary download) No compiler required! The plugin automatically downloads pre-built binaries from GitHub releases.
Using lazy.nvim
Minimal installation:
{
"esmuellert/codediff.nvim",
cmd = "CodeDiff",
}
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/codediff.nvim",
cmd = "CodeDiff",
opts = {
-- 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
-- Conflict sign highlights (for merge conflict views)
-- Accepts highlight group names or hex colors (e.g., "#f0883e")
-- nil = use default fallback chain
conflict_sign = nil, -- Unresolved: DiagnosticSignWarn -> #f0883e
conflict_sign_resolved = nil, -- Resolved: Comment -> #6e7681
conflict_sign_accepted = nil, -- Accepted: GitSignsAdd -> DiagnosticSignOk -> #3fb950
conflict_sign_rejected = nil, -- Rejected: GitSignsDelete -> DiagnosticSignError -> #f85149
},
-- Diff view behavior
diff = {
layout = "side-by-side", -- Diff layout: "side-by-side" (two panes) or "inline" (single pane with virtual lines)
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)
ignore_trim_whitespace = false, -- Ignore leading/trailing whitespace changes (like diffopt+=iwhite)
hide_merge_artifacts = false, -- Hide merge tool temp files (*.orig, *.BACKUP.*, *.BASE.*, *.LOCAL.*, *.REMOTE.*)
original_position = "left", -- Position of original (old) content: "left" or "right"
conflict_ours_position = "right", -- Position of ours (:2) in conflict view: "left" or "right"
conflict_result_position = "bottom", -- "bottom" (default): result below diff panes or "center": result between diff panes (three columns)
conflict_result_height = 30, -- Height of result pane in bottom layout (% of total height)
conflict_result_width_ratio = { 1, 1, 1 }, -- Width ratio for center layout panes {left, center, right} (e.g., {1, 2, 1} for wider result)
cycle_next_hunk = true, -- Wrap around when navigating hunks (]c/[c): false to stop at first/last
cycle_next_file = true, -- Wrap around when navigating files (]f/[f): false to stop at first/last
jump_to_first_change = true, -- Auto-scroll to first change when opening a diff: false to stay at same line
highlight_priority = 100, -- Priority for line-level diff highlights (increase to override LSP highlights)
compute_moves = false, -- Detect moved code blocks (opt-in, matches VSCode experimental.showMoves)
},
-- 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)
indent_markers = true, -- Show indent markers in tree view (│, ├, └)
initial_focus = "explorer", -- Initial focus: "explorer", "original", or "modified"
icons = {
folder_closed = "", -- Nerd Font folder icon (customize as needed)
folder_open = "", -- Nerd Font folder-open icon
},
view_mode = "list", -- "list" or "tree"
flatten_dirs = true, -- Flatten single-child directory chains in tree view
file_filter = {
ignore = { ".git/**", ".jj/**" }, -- Glob patterns to hide (e.g., {"*.lock", "dist/*"})
},
focus_on_select = false, -- Jump to modified pane after selecting a file (default: stay in explorer)
visible_groups = { -- Which groups to show (can be toggled at runtime)
staged = true,
unstaged = true,
conflicts = true,
},
},
-- History panel configuration (for :CodeDiff history)
history = {
position = "bottom", -- "left" or "bottom" (default: bottom)
width = 40, -- Width when position is "left" (columns)
height = 15, -- Height when position is "bottom" (lines)
initial_focus = "history", -- Initial focus: "history", "original", or "modified"
view_mode = "list", -- "list" or "tree" for files under commits
},
-- Keymaps in diff view
keymaps = {
view = {
quit = "q", -- Close diff tab
toggle_explorer = "<leader>b", -- Toggle explorer visibility (explorer mode only)
focus_explorer = "<leader>e", -- Focus explorer panel (explorer mode only)
next_hunk = "]c", -- Jump to next change
prev_hunk = "[c", -- Jump to previous change
next_file = "]f", -- Next file in explorer/history mode
prev_file = "[f", -- Previous file in explorer/history mode
diff_get = "do", -- Get change from other buffer (like vimdiff)
diff_put = "dp", -- Put change to other buffer (like vimdiff)
open_in_prev_tab = "gf", -- Open current buffer in previous tab (or create one before)
close_on_open_in_prev_tab = false, -- Close codediff tab after gf opens file in previous tab
toggle_stage = "-", -- Stage/unstage current file (works in explorer and diff buffers)
stage_hunk = "<leader>hs", -- Stage hunk under cursor to git index
unstage_hunk = "<leader>hu", -- Unstage hunk under cursor from git index
discard_hunk = "<leader>hr", -- Discard hunk under cursor (working tree only)
hunk_textobject = "ih", -- Textobject for hunk (vih to select, yih to yank, etc.)
show_help = "g?", -- Show floating window with available keymaps
align_move = "gm", -- Temporarily align moved code blocks across panes
toggle_layout = "t", -- Toggle between side-by-side and inline layout
},
explorer = {
select = "<CR>", -- Open diff for selected file
hover = "K", -- Show file diff preview
refresh = "R", -- Refresh git status
toggle_view_mode = "i", -- Toggle between 'list' and 'tree' views
stage_all = "S", -- Stage all files
unstage_all = "U", -- Unstage all files
restore = "X", -- Discard changes (restore file)
toggle_changes = "gu", -- Toggle Changes (unstaged) group visibility
toggle_staged = "gs", -- Toggle Staged Changes group visibility
-- Fold keymaps (Vim-style)
fold_open = "zo", -- Open fold (expand current node)
fold_open_recursive = "zO", -- Open fold recursively (expand all descendants)
fold_close = "zc", -- Close fold (collapse current node)
fold_close_recursive = "zC", -- Close fold recursively (collapse all descendants)
fold_toggle = "za", -- Toggle fold (expand/collapse current node)
fold_toggle_recursive = "zA", -- Toggle fold recursively
fold_open_all = "zR", -- Open all folds in tree
fold_close_all = "zM",
Related Skills
node-connect
337.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
337.4kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.2kCommit, push, and open a PR
