Skip to content
| Marketplace
Sign in
Visual Studio Code>SCM Providers>CodeDiffNew to Visual Studio Code? Get it now.
CodeDiff

CodeDiff

Marko Ivankovic

| (0) | Free
Syntax-aware diff highlighting, backed by the codediff CLI
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

CodeDiff for VS Code

CI License: AGPL v3+

Syntax-aware diff highlighting in VS Code, backed by the codediff CLI.

Instead of aligning two files line by line, codediff parses both sides with tree-sitter and matches their syntax trees, so a change is reported as what it structurally is — an insertion, deletion, update, or move — rather than as whichever lines happened to line up. This extension paints that verdict onto real editors as decorations.

Status

Early, but complete enough to use. Everything below the editor — spawning codediff, parsing its output, converting its byte columns, reading blobs out of git — is covered by tests that run in CI. The editor glue itself (decorations, menus, prompts) has no automated coverage, because none of it can run outside a VS Code host; treat those parts as reviewed rather than proven.

Diff two files from disk ✅ works
Insert / delete / update / move highlighting ✅ works
"Moved to line N" on hover ✅ works
Correct columns on non-ASCII lines ✅ works, and tested
Diffing against a git revision, from the SCM view ✅ works
Diffing the working copy against the last save ✅ works
Install prompt when the binary is missing ✅ works
Bundled binary, per platform ✅ works — see Requirements

Installing

Search for CodeDiff in the Extensions view, or:

  • VS Code — the Marketplace listing, or code --install-extension ivankovic.codediff.
  • VSCodium, Cursor, Windsurf and other non-Microsoft builds — Open VSX, which those editors search by default.
  • Any editor, offline — download a .vsix from the releases page and install it with code --install-extension codediff-<platform>.vsix. Take the one matching your platform to get the bundled binary, or codediff-fallback.vsix to use a codediff from PATH.

Requirements

The codediff binary. Platform-specific builds of this extension bundle it, so on those there is nothing to install:

Platform Bundled?
Linux x64 / arm64 ✅
macOS Intel / Apple silicon ✅
Windows x64 ✅
Everything else — Windows on ARM, Alpine/musl containers ❌ falls back to PATH

Alpine is deliberately unbundled: a linux-x64 build carries a glibc binary that dies on musl with an unreadable loader error, so those users get the binary-free fallback build and the PATH lookup instead.

Which binary gets run, in order:

  1. codediff.binaryPath, if you have set it to anything other than the default. It wins unconditionally, so point it at your own build to use that.
  2. The bundled binary, if this build carries one.
  3. codediff on PATH.

Step 2 exists for one failure in particular: a VS Code launched from Finder or the Dock does not inherit a login shell's PATH, so a codediff installed to ~/.cargo/bin is invisible to it and the extension reports a missing binary you can plainly run in a terminal.

If you need to install it yourself, see codediff's installation instructions — cargo install codediff, a pre-built binary from a release, nix run github:ivankovic/codediff, or one of the distribution packages.

Usage

Command What it diffs
CodeDiff: Diff Two Files… Two files you pick.
CodeDiff: Diff With HEAD The committed version against your working copy.
CodeDiff: Diff With Revision… Any ref git show accepts — a branch, a tag, HEAD~3 — against your working copy.
CodeDiff: Diff With Last Saved What is on disk against what you have typed but not saved.
CodeDiff: Clear Highlights Removes the painting from every visible editor.

The three git-aware commands are also on the right-click menu of a file in the Source Control view and of an editor tab. In every one of them the left pane is the before side, matching codediff.nvim's diff_this.

Files pulled out of git are written to the extension's own storage directory under their real basename — HEAD/parser.ts, not a scratch name — because codediff picks a tree-sitter grammar from the path. A blob written to a nameless temp file gets no grammar and silently falls back to a plain line diff. They are swept a day later, at the next activation.

Settings

Setting Default Meaning
codediff.binaryPath codediff Path to, or name of, the binary. Looked up on PATH when it is a bare name.
codediff.renderMode default Which ranges get painted: default, minimal, full, or custom.

renderMode is the one that decides how much you see:

  • default defers to codediff's own config — the nearest .codediff.toml at or above the directory of the file you are diffing, else your user-level one. A project can pin its own render options this way, and the same two files then paint the same way however VS Code was launched.
  • minimal and full pass --minimal/--full, the two presets, overriding that config.
  • custom uses the six options below and ignores codediff's config entirely.

The six painting options

These are the whole of what codediff's terminal UI offers under its M panel, and they apply only when codediff.renderMode is custom — VS Code has no way to grey out a setting that does not currently apply, so changing one while the mode is anything else does nothing and says nothing.

Setting Default What turning it on does
codediff.render.leadingWhitespace true Keeps the whitespace a range starts with, on every line of it.
codediff.render.structuralPunctuation true Paints ranges that are only brackets and separators. Operators are never dropped — < to <= is the whole edit.
codediff.render.wholePairUpdates false Highlights an updated pair whole rather than just the part that differs.
codediff.render.paintReindentOnlyMoves true Calls a pure reindent a move.
codediff.render.paintDisplacedMoves true Calls a node pushed along by a neighbouring edit a move.
codediff.render.paintResizedMoves true Reports moves whose two sides are different sizes.

The defaults are codediff's own, which are its full preset — note that is not all six on, because wholePairUpdates is off in both presets. It changes which ranges the diff has rather than how much of a decided range is painted, so it sits on a different axis. Switching to custom therefore changes nothing until you toggle something.

The terminal UI's other settings have no counterpart here on purpose: its theme and custom palette are replaced by the colour IDs below, which follow your VS Code theme, and its panel layout and node highlight describe a terminal UI this extension does not have — VS Code owns the panes.

Under the hood custom writes a small config file into the extension's storage and points codediff's CODEDIFF_CONFIG at it, which is the one layer that outranks every .codediff.toml. That is why custom ignores a project's config where default respects it.

Colours

Each highlight has its own registered colour ID, so you can retune one without touching anything else in the editor:

Operation Colour ID Default on dark Composited on #1e1e1e
insert codediff.insertBackground #32d74bb3 #2ca03e
delete codediff.deleteBackground #ff3b30b3 #bc322b
update codediff.updateBackground #ff8c1ab3 #bc6b1b
move codediff.moveBackground #5c5d64cc #505056

All four are literals, at 70% alpha on dark. None of them references a theme key, and insert and delete are the interesting case: diffEditor.insertedTextBackground and diffEditor.removedTextBackground are the obvious references, and this extension used them, but both sit at 20% alpha — right for the diff editor, which washes whole lines with colour, and far too faint here, where what gets painted is often a single identifier. Update is an orange rather than the olive it started as so that it cannot read as a dimmer insert.

Alpha rather than opaque colour, so each still composites over the theme's own editor background. contributes.colors takes one value per theme kind — light, dark, high-contrast — not per theme, so a single dark value has to serve every dark theme. If one of them sits badly in yours, override it, scoped to that theme if you like:

"workbench.colorCustomizations": {
  "codediff.moveBackground": "#5c5d64",
  "[Solarized Light]": { "codediff.moveBackground": "#d8d3c0" }
}

That is the reason these are contributed IDs rather than direct references to shared keys: retuning editor.symbolHighlightBackground would repaint find-match highlights across the whole editor, while codediff.moveBackground touches nothing but this extension.

How it works

codediff --mode json BEFORE AFTER prints one JSON object describing each side's changed ranges, their operation, a move's real counterpart range in the other file, and the nearest enclosing declaration. This extension parses that and calls setDecorations; it never parses ANSI escapes out of a terminal diff tool.

codediff reports columns as byte offsets. VS Code's Position.character is UTF-16 code units. They agree exactly while a line is all-ASCII and diverge the moment it is not — which is what makes this the easiest thing in the whole integration to get wrong. Measured against the real binary: for the line x = "ααα" + bbb, codediff reports column 15 where VS Code needs 12. src/columns.ts does the conversion, and src/test/columns.test.ts pins it against Buffer.byteLength at every byte offset of a mixed ASCII/Latin-1/CJK/emoji line.

(Neovim needs no such conversion — nvim_buf_set_extmark takes byte columns directly — which is why codediff emits bytes rather than a second coordinate space it could disagree with itself about. See codediff.nvim.)

Contributing

See CONTRIBUTING.md. In short: npm ci, then npm run lint and npm test.

License

AGPL-3.0-or-later — see LICENSE, the same licence as codediff itself.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft