Metadata-Version: 2.4
Name: logicdiff
Version: 0.1.0
Summary: A whitespace- and reflow-blind diff: folds respacing AND line re-wrapping that git diff -w can't, and tells you if a change is logical or just formatting. Zero dependencies.
Author: yyfjj
License: MIT
Project-URL: Homepage, https://github.com/jjdoor/logicdiff-py
Project-URL: Repository, https://github.com/jjdoor/logicdiff-py
Project-URL: Issues, https://github.com/jjdoor/logicdiff-py/issues
Keywords: diff,whitespace,reflow,format,git,code-review,cli,ci,devtools
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Version Control
Classifier: Topic :: Utilities
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# logicdiff

**A whitespace- and reflow-blind diff.** A pull request reindents a file and
rewraps a few long lines, and now `git diff` shows 80 changed lines — but did
anything *actually* change? `logicdiff` answers that: it folds away pure
formatting (respacing **and** line reflow) and shows only the logical changes.

```bash
logicdiff old.js new.js
#   only formatting differs - no logical change (a line diff would show 80 changed lines)

logicdiff a.js b.js
#   --- a.js
#   +++ b.js
#   -42:   const total = price * qty;
#   +51:   const total = price + qty;
#
#   1 token removed, 1 added across 2 logical lines (78 lines folded as reflow/whitespace)
```

Exit `0` when the change is formatting-only (or identical), `1` when there's a
real logical change — so CI can ask "is this PR just a reformat?" Zero
dependencies, language-agnostic, also on npm (`npx logicdiff`) — the two
builds produce **byte-for-byte identical** output.

## Why not `git diff -w`?

`git diff -w` (ignore-all-space) folds *respacing* — but it is still
line-anchored, so it **cannot fold reflow**. Re-wrap a function signature across
three lines and `git diff -w` still shows 1 removed + 3 added, even though not a
single token changed. That exact gap is [GitHub discussion #20610]
("Ignore Format Changes in Diff"), open and unanswered for years.

`difftastic` solves it beautifully with per-language tree-sitter parsing — but
it's a multi-megabyte binary, needs a grammar for each language (config/log/DSL
files fall back to text), and it's a *display* tool with no "is this
formatting-only?" exit code.

`logicdiff` is the lightweight middle ground: **zero-config, zero-dependency,
language-agnostic** (works on any text — code, YAML, logs, DSLs), folds *both*
whitespace and reflow, and gives a one-shot CLI answer plus a CI exit code.

## How it works

It tokenizes each file into a sequence of tokens — a token is a run of
`[A-Za-z0-9_]` or a single punctuation character, and **whitespace is dropped**.
So `a+b`, `a + b`, and `a +\n  b` all become the same token stream `[a, + , b]`:
respacing and line breaks become invisible. It then runs the canonical
[Myers diff] on the token streams. If the streams are equal, the change is
formatting-only. If not, the changed tokens are mapped back to their line
numbers and shown.

Because it has no language parser, whitespace **inside string literals** is also
ignored — `x = "a b"` and `x = "a  b"` are "formatting only", exactly like
`git diff -w`. That's a deliberate, documented limitation, not a bug.

## Usage

```bash
logicdiff old new            # human diff (or "only formatting differs")
logicdiff old new --stat     # just the counts, machine-friendly key=value
logicdiff old new --json     # structured output (byte-identical both builds)
logicdiff old new -q         # no output, exit code only (the CI gate)
cat new | logicdiff old -     # - reads stdin
```

`--color=auto|always|never`, `--max-tokens N` (bail over N tokens, default 2,000,000).
Two wildly dissimilar inputs (a huge edit distance) also bail with exit `2` instead of
risking the heap — logicdiff is for spotting a real change inside a reformat, not for
diffing unrelated files.

Exit codes: `0` identical or formatting-only · `1` logical changes · `2` error.

```yaml
# CI: warn when a PR is more than a reformat
- run: logicdiff "$BASE" "$HEAD" -q || echo "::warning::real code change, review carefully"
```

## Install

```bash
pip install logicdiff # or pipx run logicdiff
npm i -g logicdiff    # Node build, identical behaviour
```

Python ≥ 3.8 or Node ≥ 18. No dependencies.

[GitHub discussion #20610]: https://github.com/orgs/community/discussions/20610
[Myers diff]: https://blog.jcoglan.com/2017/02/12/the-myers-diff-algorithm-part-1/

## License

MIT
