OmniDiff
Kenmerken:
- Robuust: Kan 99,95% van de code-wijzigingen analyseren.
- Content-bewust: 98,8% van de wijzigingen wordt geanalyseerd met behulp van content-specifieke algoritmen.
Prestaties en Accuraatheid
| Content | Snelheid (< 100ms) | Accuraat (Perfect) | Accuraat (Bijna perfect) |
|---|---|---|---|
| Code | 98% | 70% | 92% |
| Afbeeldingen | 96% | 69% | 91% |
| Cursors | 100% | 85% | 100% |
| Fonts | 95% | 82% | 100% |
| Archieven | 88% | 87% | 87% |
| Berichtenkatalogi | 100% | 83% | 83% |
| PDF's | 57% | 100% | 100% |
Snelheid is gemeten op een T14s, Intel Core i7-1370P met 32 GB RAM. PDF's hebben minder dan tien beoordeelde testgevallen.
Voor een visuele demonstratie kunnen twintig echte codewijzigingen, opgenomen vanuit de command-line tool en naast elkaar vergeleken in Unix diff en OmniDiff, worden bekeken in de browser op: ivankovic.github.io/omnidiff/showcase/. Hier zijn ook voorbeelden te vinden van OpenDocument-bestanden, gecompileerde vertalingskatalogi en stilstaande en geanimeerde afbeeldingen.
---
Installatie
Vanuit broncode
cargo install --locked omnidiff
Dit commando bouwt OmniDiff vanuit de broncode met de versies van de afhankelijkheden waarmee het is getest. U heeft een C-compiler op uw PATH en een Rust-toolchain (rustc 1.92 of later) nodig. De build compileert elke tree-sitter grammar vanuit C. De eerste cargo install duurt enkele minuten vanwege deze compilatie en het lto = "fat" release-profiel.
Prebuilt binaries
Prebuilt binaries voor Linux, macOS (Intel en Apple Silicon) en Windows zijn bijgevoegd bij elke GitHub release.
Homebrew
Voor macOS en Linux:
brew install ivankovic/omnidiff/omnidiff
Debian en Ubuntu
.deb-pakketten voor amd64 en arm64 zijn beschikbaar in een ondertekend apt-repository:
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://ivankovic.github.io/omnidiff/apt/omnidiff-archive-keyring.gpg \
| sudo tee /etc/apt/keyrings/omnidiff-archive-keyring.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/omnidiff-archive-keyring.gpg] \
https://ivankovic.github.io/omnidiff/apt stable main" \
| sudo tee /etc/apt/sources.list.d/omnidiff.list > /dev/null
sudo apt update && sudo apt install omnidiff
Nix en NixOS
Op NixOS, of overal waar Nix is geïnstalleerd:
nix run github:ivankovic/omnidiff
Als flakes niet zijn ingeschakeld in uw Nix-configuratie, voeg dan --extra-experimental-features 'nix-command flakes' toe na nix.
Arch en Gentoo
Recepten voor Arch en Gentoo staan in de map packaging/: de PKGBUILD kan lokaal worden gebouwd met makepkg -si, en de Gentoo ebuild is klaar voor een overlay.
---
Editor integratie
- VS Code: VS Code staat extensies momenteel niet toe om de ingebouwde diff-weergave te vervangen. De API is upstream geïmplementeerd maar nog niet uitgebracht; de extensie zal dit adopteren zodra dit beschikbaar is. De extensie is beschikbaar als
omnidiff-vscode. Zoek naar "OmniDiff" in de Extensions view, of gebruik:
code --install-extension ivankovic.omnidiff. Beschikbaar ook op Open VSX voor VSCodium, Cursor en Windsurf.
- Neovim: Beschikbaar via
omnidiff.nvim.
---
Gebruik van OmniDiff
De interactieve TUI
omnidiff # Open een lege viewer; druk op 'o' om een bestand te kiezen
omnidiff VOOR NA # Open direct de diff van twee bestanden
Druk op ? in de viewer voor de volledige lijst met toetscombinaties.
De TUI gebruikt 24-bit kleur wanneer de terminal dit ondersteunt via COLORTERM=truecolor, anders worden de dichtstbijzijnde 256 kleuren gebruikt. Als uw terminal 24-bit kleur ondersteunt maar dit niet communiceert, voer dan uit: export COLORTERM=truecolor.
In een browser
Voor het beoordelen van wijzigingen in een browser, zie codereview. Let op: codereview is versie v0.0.0; gebruik dit op eigen risico.
Headless / batch-modus
omnidiff --headless VOOR NA
Of gebruik het synoniem --batch. Dit print de diff als platte tekst (optioneel met kleur) in plaats van de TUI te openen. Dit is geschikt voor scripts of CI. De headless-modus start automatisch wanneer stdout geen terminal is (bijvoorbeeld bij het pipen naar less of redirecten naar een bestand). Daarom werkt omnidiff VOOR NA | less zonder de vlag.
OmniDiff klapt lange reeksen ongewijzigde regels in. Er worden 3 regels context aan weerszijden van een wijziging behouden (aanpasbaar met --context N), conform de conventie van diff -u. OmniDiff prefixeert elk fragment (hunk) met de dichtstbijzijnde omhullende functie, klasse of struct-regel, wanneer deze niet anders zichtbaar is.
Kleuren staan standaard aan; gebruik --color never of zet NOCOLOR=1 om ANSI-kleuren uit te schakelen. --color always dwingt kleuren af, zelfs onder NOCOLOR.
OmniDiff verlaat het programma met code 0 bij succes en 2 bij een fout. Voor scripting kan --exit-code worden meegegeven om ook code 1 te krijgen wanneer de bestanden verschillen, conform de diff(1) conventie.
JSON output
omnidiff --mode json VOOR NA
Dit print de diff als één JSON-object. De velden zijn beschreven in src/tui/json_output.schema.json.
---
Integraties
Git integratie
OmniDiff is een git difftool-backend. Gebruik de interactieve setup-wizard:
omnidiff git configure
Handmatige configuratie:
git config difftool.omnidiff.cmd 'omnidiff "$LOCAL" "$REMOTE"'
git difftool --tool=omnidiff
Voer git config diff.tool omnidiff uit om OmniDiff standaard te maken voor git difftool. Om de bevestigingsvraag "view diff ... [Y/n]?" uit te schakelen, voer uit: git config difftool.prompt false.
Gebruik: git difftool opent de interactieve TUI. git diff en git log -p doen dit nooit, omdat zij hun output via een pager sturen en een full-screen TUI niet op een pipe kan tekenen. In dat geval valt OmniDiff terug op platte tekst. Voor de interactieve viewer vanuit git moet u git difftool gebruiken. Over SSH is mogelijk ssh -t nodig voor een pseudo-terminal.
OmniDiff werkt ook direct met git diff en git log -p via GITEXTERNALDIFF:
GIT_EXTERNAL_DIFF=omnidiff git diff
Jujutsu (jj) integratie
jj leest geen git-instellingen, dus heeft het een eigen configuratie nodig. Gebruik de setup-wizard:
omnidiff jj configure
Handmatige configuratie:
jj config set --user merge-tools.omnidiff.program omnidiff
jj config set --user merge-tools.omnidiff.diff-args '["$left","$right"]'
jj config set --user merge-tools.omnidiff.diff-invocation-mode file-by-file
Dit registreert jj diff --tool omnidiff. Om dit de standaard te maken voor jj diff:
jj config set --user ui.diff-formatter omnidiff
Gebruik --repo in plaats van --user voor configuratie van alleen het huidige repository. De instelling diff-invocation-mode = "file-by-file" is vereist omdat OmniDiff twee bestanden difft, terwijl jj standaard twee directory-bomen overhandigt.
Gebruik: jj diff draait de formatter onder een pager, waardoor OmniDiff in de niet-interactieve tekstmodus rendert. Omdat jj geen equivalent heeft van de interactieve per-bestand viewer van git difftool, moet u voor de full-screen TUI in een jj-repo direct omnidiff VOOR NA uitvoeren.
---
Ondersteunde Content
De taal wordt gedetecteerd op basis van de bestandsextensie. Bestanden met een onbekende extensie worden als platte tekst (regel voor regel) behandeld.
Structurele Diffing (Tree-sitter)
De volgende 25 talen worden geparsed met een tree-sitter grammar en structureel vergeleken:
| Taal | Extensies |
|---|---|
| C | .c, .h |
| C# | .cs |
| C++ | .cc, .cpp, .cxx, .hpp, .hh, .hxx |
| CSS | .css, .scss |
| Go | .go |
| HTML | .html, .htm |
| Java | .java |
| JavaScript | .js, .mjs, .cjs, .jsx |
| JSON | .json |
| Kotlin | .kt |
| Lua | .lua |
| Perl | .pl, .pm |
| PHP | .php |
| Python | .py, .pyi, .pyw |
| R | .r |
| Ruby | .rb |
| Rust | .rs |
| Scala | .scala |
| Shell (Bash) | .bash, .sh |
| Swift | .swift |
| TSX | .tsx |
| TypeScript | .ts, .mts, .cts |
| Vimscript | .vim |
| XML | .xml, .xht, .xhtml, .svg, .glif, .plist, .ui, .qrc, .glade, .xib, .storyboard, .xaml, .vcxproj, .filters, .csproj, .fsproj, .vbproj, .props, .targets, .nuspec, .resx, .wxs, .iml, .manifest, .config, .policy, .xsd, .xsl, .xslt, .xlf, .xliff, .kml, .gpx, .rss, .atom, .graphml, .dae |
| YAML | .yaml, .yml |
Herkenning via extensie, maar diffed als platte tekst: Bazel (.bazel), Dart (.dart), Emacs Lisp (.el), Markdown (.md, .markdown), Protocol Buffers (.proto), SQL (.sql).
Niet-tekstuele Content
Bestanden die geen tekst zijn, worden herkend aan hun bytes en diffed op basis van hun inhoud:
| Content | Formaten | Methode van Diffing |
|---|---|---|
| Afbeeldingen | PNG, JPEG, GIF, WebP, BMP, ICO, TIFF | Pixel voor pixel; animaties frame voor frame. |
| Archieven | zip (incl. jar, Office, EPUB), tar, gzip, xz, bzip2 | Bestand voor bestand; inclusief geneste archieven; Java class-bestanden als lijst van velden en methoden. |
| Fonts | TrueType, OpenType, WOFF, WOFF2, EOT | Glyf voor glyf; inclusief namen en metrieken. |
| Cursors | Windows .cur en .ani, X cursors, Hyprland .hlc | Grootte voor grootte en frame voor frame. |
| Berichtenkatalogi | gettext .mo, Qt .qm | Bericht voor bericht. |
| Documenten | Pagina voor pagina, waarbij elke pagina wordt getekend. | |
| Tekst in andere coderingen | UTF-16 en UTF-32 met BOM | Als tekst, zoals elk ander bestand. |
Alleen de leden die zijn gewijzigd worden geopend. Elke wijziging wordt benoemd naar de zichtbaarheid voor de lezer: invisible (alleen bytes verschillen), imperceptible, artifacts (compressie/resampling), edited, redrawn of replaced. Voor tekst worden whitespace, formatting en rewritten gebruikt.
De TUI toont afbeeldingen als afbeeldingen: via kitty, sixel of iTerm2 protocollen, en via Unicode half-blocks elders. Met b kan worden gewisseld naar half-blocks. De omgevingsvariabele OMNIDIFF_GRAPHICS kan dit overschrijven.
---
Licentie
Copyright (C) 2026 Marko Ivankovic. Dit programma is vrije software: u mag het herdistribueren en/of wijzigen onder de voorwaarden van de GNU Affero General Public License versie 3.
Commerciële licentie: Voor organisaties die AGPL-software niet kunnen gebruiken, is een commerciële licentie beschikbaar via een maandelijks abonnement via GitHub Sponsors. Dit dekt intern gebruik zonder de broncode-openbaarmakingsverplichtingen van de AGPL.
---
Leidende Principes
Snelheid (Fast)
Het doel is een mediane diff in 100ms of minder, en een 99ste-percentiel diff in 1000ms of minder. Beide doelen zijn behaald. Metingen op een Intel Core i7-1370P (32 GB RAM):
- p50: 4,2ms
- p90: 35,1ms
- p99: 177ms
- Langzaamste: 482ms
Voor andere content (inclusief decodering zoals het uitpakken van archieven of tekenen van PDF-pagina's):
- Afbeeldingen: p50 1,8ms, p99 526ms (96,1% < 100ms)
- Cursors: p50 0,6ms, p99 15ms (100% < 100ms)
- Fonts: p50 6,4ms, p99 826ms (95% < 100ms)
- Archieven: p50 2,6ms, p99 1.938ms (88% < 100ms)
- Berichtenkatalogi: p50 0,4ms, p99 4,7ms (100% < 100ms)
- PDF's: p50 69ms, p99 985ms (57% < 100ms)
Robuustheid (Robust)
Het doel is om 100% van alle commits te kunnen verwerken. Getest op de git-commit geschiedenis van ongeveer 7.500 open-source repositories (Gentoo Linux lijst). Van 442.530 paren in 25 talen voltooiden 442.322 (99,95%) succesvol.
Wat betreft alle bestanden (inclusief afbeeldingen, fonts en archieven): 98,8% worden diffed als tekst of via hun content. Wat overblijft is voornamelijk tekst in legacy-coderingen, gecompileerde objecten, audio en specifieke EOT-fonts.
Accuraatheid (Accurate)
OmniDiff moet overeenkomen met de menselijke interpretatie van een wijziging.
- Doel 1: 90% van de testgevallen met nul mismatchte bytes.
- Doel 2: 99% van de testgevallen met maximaal 1% mismatchte bytes.
Huidige resultaten (op basis van 1.419 handmatig gelabelde gevallen):
--fullpreset: 60,0% nul mismatch, 87,5% ≤ 1% mismatch.--minimalpreset: 69,6% nul mismatch, 91,5% ≤ 1% mismatch.
Voor andere content (beoordeeld op basis van perfect/bijna-perfect):
- Afbeeldingen: 69% perfect, 91% bijna-perfect.
- Cursors: 85% perfect, 100% bijna-perfect.
- Fonts: 82% perfect, 100% bijna-perfect.
- Archieven: 87% perfect, 87% bijna-perfect.
- Berichtenkatalogi: 83% perfect, 83% bijna-perfect.
- PDF's: 100% perfect, 100% bijna-perfect.
---
AI-beleid
Dit project maakt substantieel gebruik van AI-assistentie, momenteel Claude Code. De meeste commits vermelden dit met een Co-Authored-By trailer en een link naar de sessie. Dit project beschouwt AI-assistentie niet als een minderwaardige manier van software schrijven.
Bijdragen worden momenteel niet geaccepteerd om de ontwikkelsnelheid hoog te houden. Wanneer dit verandert, zullen AI-ondersteunde bijdragen welkom zijn, mits op dezelfde manier opengelegd: degene die het werk indient, is verantwoordelijk voor het begrijpen ervan en het ondersteunen ervan.
Groetjes,