Skip to content

ekil1100/diffo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

diffo wordmark

diffo

diffo is a terminal Git diff review tool for local review before commit or push. It opens the current working tree diff by default, including untracked files, supports git diff-style targets, tracks file-level reviewed state, stores inline comments, and exposes review data through script-friendly CLI commands.

The project is implemented in Zig and targets Zig 0.16.0.

Why diffo?

Use diffo when you want a fast local pass over changes before a commit, push, or pull request. It keeps the review loop in the terminal, remembers which file patches you have already checked, and stores comments outside the repository so review notes do not dirty the working tree.

Feature Tour

  • Review unstaged, staged, and untracked working tree changes by default.
  • Review explicit Git targets such as HEAD~1..HEAD, branches, ranges, --cached, and pathspecs.
  • Browse diffs in a terminal UI with a right-side file list.
  • Toggle inline and split diff views.
  • Mark files as reviewed or unreviewed.
  • Automatically invalidate reviewed state when a file patch changes.
  • Add single-line or multi-line comments from the TUI or CLI.
  • List comments and review state as text or JSON for scripts and agents.
  • Store state outside the repository using XDG state paths.
  • Use Catppuccin Mocha as the built-in default theme.
  • Validate Base16/Base24 theme files.
  • Apply syntax highlighting when terminal color support is available. Bundled Tree-sitter grammars are used for Zig, TypeScript/TSX, JavaScript, Rust, C, C++, and Python files.

Install

Requirements:

  • Zig 0.16.0
  • Git
  • A POSIX-like terminal for the interactive TUI

Install Zig with Homebrew:

brew install zig

If Zig is already installed through Homebrew:

brew upgrade zig
zig version

Build from source:

zig build

The executable is written to:

zig-out/bin/diffo

Install to ~/.local/bin with just:

just install

Or install manually after building:

mkdir -p ~/.local/bin
cp zig-out/bin/diffo ~/.local/bin/diffo
chmod +x ~/.local/bin/diffo

Make sure ~/.local/bin is on your PATH before running diffo from any repository.

Run tests:

zig build test

Quick Start

From inside a Git repository:

diffo

Or, from this project checkout:

./zig-out/bin/diffo

Review an explicit target:

diffo HEAD~1..HEAD
diffo main...feature
diffo --cached
diffo -- src/

When stdout is not a TTY, diffo renders a static diff screen instead of entering the interactive alternate screen.

Interactive Keys

Key Action
j / k Move down / up within the current file diff
/ Move down / up within the current file diff
G / gg 跳到当前文件 diff 的底部 / 顶部
PageUp / PageDown Scroll by a larger step
J / K Move to next / previous file
n / N Jump to next / previous change
C Toggle unfold / fold mode
z Toggle the fold at the cursor in fold mode
Z Toggle all folds in the current file in fold mode
v Toggle stacked / split diff view
r Toggle current file reviewed state
c Add a comment at the current diff line
V Start a multi-line selection
y Copy the selected diff rows, or the current row, to the clipboard
Esc Clear the current selection
u Jump to the first unreviewed file
? Toggle help
q Quit

Mouse support is enabled in the TUI:

  • Scroll wheel over the diff scrolls the current file.
  • Scroll wheel over the file tree moves between files.
  • Clicking a diff row moves the cursor.
  • Dragging over diff rows extends the selection for copying or commenting.
  • Clicking a file-tree row opens that file.

When running inside tmux, mouse events must be enabled in tmux as well:

set -g mouse on

CLI Commands

Show help:

diffo --help

List comments:

diffo comments list
diffo comments list --file src/main.zig
diffo comments list --json

Get one comment:

diffo comments get cmt_0123456789abcdef
diffo comments get cmt_0123456789abcdef --json

清理当前 review target 中已经过期的注释(锚点状态为 stalemissing),或用 --all 删除仓库中保存的所有注释:

diffo comments clean
diffo comments clean --all
diffo comments clean --dry-run
diffo comments clean --file src/main.zig
diffo comments clean --json

Add a comment without opening the TUI:

diffo comments add --file src/main.zig --line 42 --body "Check this branch."
diffo comments add --file src/main.zig --line 42 --end 45 --body "Consider extracting this block."

Show review status:

diffo review status
diffo review status --file src/main.zig
diffo review status --json

Mark a file:

diffo review mark --file src/main.zig --reviewed
diffo review mark --file src/main.zig --unreviewed

Theme commands:

diffo themes list
diffo themes validate path/to/theme.yaml

Debug Git command failures:

diffo --debug-git
diffo review status --debug-git

JSON Output

Review status output includes stable top-level fields:

{
  "schema_version": 1,
  "repository_id": "repo_...",
  "review_target_id": "target_...",
  "files": [
    {
      "file_path": "src/main.zig",
      "status": "unreviewed",
      "patch_fingerprint": "sha256:...",
      "comment_count": 0
    }
  ]
}

Comment output includes file path, line range, side, body, author, match status, and anchor data:

{
  "comment_id": "cmt_...",
  "file_path": "src/main.zig",
  "start_line": 42,
  "end_line": 45,
  "side": "new",
  "body": "Consider extracting this block.",
  "author": "like",
  "match_status": "exact",
  "anchor": {
    "hunk_header": "@@ -40,3 +42,6 @@",
    "patch_fingerprint": "sha256:...",
    "stable_line_ids": ["line_..."]
  },
  "review_target_id": "target_..."
}

match_status can be:

  • exact: the stored patch fingerprint still matches.
  • stale: the file still exists in the current diff, but the patch changed.
  • missing: the file no longer exists in the current diff.
  • relocated: reserved for future relocation support.

Storage

diffo does not write review data into the Git working tree. State is stored under:

${XDG_STATE_HOME:-$HOME/.local/state}/diffo/repos/<repo_id>/

Current files:

comments.json
review-states.json

Writes use a temporary file followed by rename, so interrupted writes should not corrupt repository contents.

Current V1 Limits

  • Tree-sitter highlighting is currently bundled for Zig, TypeScript/TSX, JavaScript, Rust, C, C++, and Python files; unsupported languages, explicit targets, large files, and unavailable source sides are shown without syntax highlighting.
  • Comment relocation is minimal: comments become stale when the patch fingerprint changes.
  • Runtime theme switching and full config loading are not implemented yet.
  • Mouse support covers click selection and scroll wheel navigation; richer filtering/search can be added later.

Development

Format sources:

zig fmt build.zig src/*.zig

Run the normal validation loop:

zig build test
zig build

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors