Metadata-Version: 2.4
Name: clang-format-inc
Version: 0.2.0
Summary: Incrementally format only changed C/C++ lines with clang-format — works in both local and CI pre-commit contexts
Author-email: Aditya Goyal <goyaladitya05@users.noreply.github.com>
License: MIT
Project-URL: Homepage, https://github.com/goyaladitya05/clang-format-inc
Project-URL: Repository, https://github.com/goyaladitya05/clang-format-inc
Project-URL: Issues, https://github.com/goyaladitya05/clang-format-inc/issues
Project-URL: Changelog, https://github.com/goyaladitya05/clang-format-inc/blob/main/CHANGELOG.md
Keywords: clang-format,pre-commit,c++,formatter,incremental,linter
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: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Dynamic: license-file

# clang-format-inc

[![CI](https://github.com/goyaladitya05/clang-format-inc/actions/workflows/ci.yml/badge.svg)](https://github.com/goyaladitya05/clang-format-inc/actions/workflows/ci.yml)
[![PyPI version](https://img.shields.io/pypi/v/clang-format-inc.svg)](https://pypi.org/project/clang-format-inc/)
[![Python versions](https://img.shields.io/pypi/pyversions/clang-format-inc.svg)](https://pypi.org/project/clang-format-inc/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

**Incremental C/C++ formatting as a pre-commit hook — format only the lines you changed.**

---

## The problem

| Tool | Issue |
|---|---|
| `mirrors-clang-format` | Reformats **entire files** — breaks diffs in large codebases |
| `git clang-format --staged` | Works locally, but **staging area is empty in CI** when pre-commit uses `--from-ref`/`--to-ref` |

`clang-format-inc` solves both: it reads the `PRE_COMMIT_FROM_REF` / `PRE_COMMIT_TO_REF` environment variables that pre-commit sets in CI mode and falls back to `--cached` (staged changes) locally.

Inspired by [`darker`](https://github.com/akaihola/darker), which does the same for Python/Black.

---

## How it works

```
pre-commit (CI, --from-ref/--to-ref)
  └─ sets PRE_COMMIT_FROM_REF, PRE_COMMIT_TO_REF
      └─ clang-format-inc
          └─ git diff -U0 $FROM_REF $TO_REF -- <files>
              └─ clang-format --lines=<start>:<end> -i <file>  ← only changed lines
pre-commit (local)
  └─ clang-format-inc
      └─ git diff -U0 --cached -- <files>
          └─ clang-format --lines=<start>:<end> -i <file>
```

The diff is parsed to extract added-line ranges per file. `clang-format` is called with `--lines=start:end` for each changed hunk — **only touched lines are reformatted.**

---

## Requirements

- Python 3.8+
- `clang-format` — installed automatically by pre-commit via `additional_dependencies` (see below), or specify a custom binary with `--binary`

---

## Usage as a pre-commit hook

Add to your `.pre-commit-config.yaml`:

```yaml
repos:
  - repo: https://github.com/goyaladitya05/clang-format-inc
    rev: v0.2.0
    hooks:
      - id: clang-format-inc
```

`clang-format` is installed automatically into the hook's virtualenv — no system-wide install needed.

### Pin a specific clang-format version

```yaml
hooks:
  - id: clang-format-inc
    additional_dependencies: ['clang-format==18.1.0']
```

### Check mode (report without fixing)

```yaml
hooks:
  - id: clang-format-inc
    args: [--check]
```

With `--check`, the hook exits non-zero if any changed line would be reformatted, but **never modifies files**. Useful in CI pipelines where you want to report issues without auto-applying fixes.

### Run locally

```bash
pre-commit run clang-format-inc --all-files
```

### Run in CI (GitHub Actions example)

```yaml
- name: Run pre-commit
  run: |
    pre-commit run clang-format-inc \
      --from-ref ${{ github.event.pull_request.base.sha }} \
      --to-ref   ${{ github.event.pull_request.head.sha }}
```

---

## CLI reference

```
clang-format-inc [options] [files ...]

Options:
  --binary PATH          Path to clang-format binary (default: clang-format)
  --style STYLE          Formatting style: file, LLVM, Google, etc. (default: file)
  --fallback-style STYLE Style to use when --style=file but no .clang-format found
  --sort-includes        Pass --sort-includes to clang-format
  --check                Don't modify files; exit non-zero if any file would be reformatted
  -p NUM                 Strip NUM leading path components from diff filenames (default: 1)
```

---

## Install from PyPI

```bash
pip install clang-format-inc
```

---

## Environment variables (set automatically by pre-commit)

| Variable | When set | Value |
|---|---|---|
| `PRE_COMMIT_FROM_REF` | CI mode (`--from-ref`) | Base commit SHA |
| `PRE_COMMIT_TO_REF` | CI mode (`--to-ref`) | Head commit SHA |

When both are set, `clang-format-inc` diffs those two commits. Otherwise it diffs the index (`--cached`).

---

## License

MIT © Aditya Goyal
