Side-by-side semantic diff tool with theme support and hookable integration
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Go 84.5%
Nix 12.7%
Python 1.7%
Ruby 1.0%
Shell 0.1%
Other 0.1%
23 1 6

Clone this repository

https://tangled.org/adriano.tngl.sh/adiff https://tangled.org/did:plc:3lekddzmkd3zyk2nhmv4k4n5/adiff
git@tangled.org:adriano.tngl.sh/adiff git@tangled.org:did:plc:3lekddzmkd3zyk2nhmv4k4n5/adiff

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

adiff#

A semantic, side-by-side diff viewer for the terminal with $EDITOR support.

Unlike traditional diff tools, adiff uses tree-sitter to parse source files into ASTs and diffs at the token level. This means pure formatting changes — re-indented blocks, reformatted function signatures, whitespace normalization — are shown as equal, while genuine logic changes are clearly highlighted.

adiff screenshot

Features#

  • Semantic diff — tree-sitter token-level diffing ignores style-only changes
  • Syntax highlighting — per-language color via Chroma
  • Live file watching — press e to open the new file in $EDITOR; adiff watches for saves and reloads automatically
  • Vim keybindingsj/k, g/G, n/p for change navigation
  • Themeable — TOML theme files with full colour control; nord built-in

Semantic Supported languages#

Bash, C, C++, Go, JavaScript, JSON, Nix, Python, Ruby, Rust, TypeScript

Supported languages#

All languages without semantic support are supported with traditional text diffs

Installation#

Nix (flake)#

inputs.adiff.url = "https://flakes.adriano.fyi/adiff";

Then add inputs.adiff.packages.${system}.default to your packages, or use the provided overlay.

Direct package reference (home-manager / NixOS environment.systemPackages):

home.packages = [ inputs.adiff.packages.${pkgs.system}.default ];

Overlay — adds pkgs.adiff to your package set:

nixpkgs.overlays = [ inputs.adiff.overlays.default ];

# Then reference it like any nixpkgs package:
home.packages = [ pkgs.adiff ];

In a NixOS or home-manager flake this typically looks like:

{
  inputs = {
    nixpkgs.url     = "github:NixOS/nixpkgs/nixos-unstable";
    home-manager.url = "github:nix-community/home-manager";
    adiff.url        = "git+https://tangled.org/adriano.tngl.sh/adiff";
  };

  outputs = { nixpkgs, home-manager, adiff, ... }: {
    homeConfigurations.yourname = home-manager.lib.homeManagerConfiguration {
      pkgs = import nixpkgs {
        system  = "x86_64-linux";
        overlays = [ adiff.overlays.default ];
      };
      modules = [
        ({ pkgs, ... }: { home.packages = [ pkgs.adiff ]; })
      ];
    };
  };
}

Usage#

adiff [flags] <old-file> <new-file>
Flag Default Description
-theme nord Theme name or path to a .toml file

Keybindings#

Key Action
j / k Move down / up
h / l Scroll left / right (8 cols)
H / L Scroll left / right (half-column jump)
0 / $ Jump to line start / end
n / p Jump to next / previous change
g / G Jump to top / bottom
s Toggle semantic ↔ text diff mode
e Open new file in $EDITOR; diff reloads on save
q Quit

Mouse / trackpad: vertical wheel scrolls rows; horizontal wheel scrolls columns.

Diff modes#

Semantic mode (default) uses the tree-sitter AST to identify which tokens actually changed. Adjacent removed/added line blocks where all tokens are identical are collapsed into equal (unhighlighted) lines. Only lines containing genuinely changed tokens are highlighted.

Text mode falls back to a standard line-level diff with no AST involvement. Toggle between modes with s.

Themes#

Themes are TOML files. adiff searches for themes in this order:

  1. Literal path (if the value contains / or ends in .toml)
  2. ~/.config/adiff/themes/<name>.toml
  3. Built-in nord

Theme format#

[meta]
name        = "mytheme"
description = "My custom theme"
author      = "you"

[chroma]
style = "nord"          # any Chroma style name

[diff]
added_bg       = "#2E4034"
added_fg       = "#A3BE8C"
removed_bg     = "#3D1F1F"
removed_fg     = "#BF616A"
equal_fg       = "#D8DEE9"
header_fg      = "#88C0D0"
line_number_fg = "#4C566A"
status_fg      = "#5E81AC"
help_fg        = "#4C566A"
cursor_symbol  = "▶"

Place custom themes at ~/.config/adiff/themes/<name>.toml and reference them with -theme <name>.

hookable integration#

hookable is a Claude Code hook runner that exposes tool call inputs as environment variables and forwards them to an arbitrary command. adiff reads these variables natively, so it can be dropped in as the --cmd to preview file changes before Claude applies them.

When invoked with no file arguments and HOOKABLE_TOOL_NAME is set, adiff constructs the before/after diff automatically:

Tool Before After
Edit Current file on disk File with old_string replaced by new_string
Write Current file on disk (empty if new) Incoming content

Claude Code hook configuration#

Add to ~/.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit",
        "hooks": [{"type": "command", "command": "hookable --interactive --no-exit-code --cmd 'adiff -i'"}]
      },
      {
        "matcher": "Write",
        "hooks": [{"type": "command", "command": "hookable --interactive --no-exit-code --cmd 'adiff -i'"}]
      }
    ]
  }
}

--interactive runs adiff under a PTY so the full TUI renders. --no-exit-code tells hookable to ignore adiff's exit code and always wait for a keypress — press y to allow the change or n to deny it.

Development#

nix develop          # CGO-aware dev shell
go test ./...        # run tests
nix build            # hermetic build → ./result/bin/adiff

Releasing#

VERSION is the single source of truth for the release version. Bump it with svu via the flake app:

nix run .#bump-version           # bump to next version (based on conventional commits)
nix run .#bump-version -- patch  # force a patch bump
nix run .#bump-version -- minor  # force a minor bump
nix run .#bump-version -- major  # force a major bump

After bumping, commit VERSION and tag the release.