# cruxlines

cruxlines analyzes a codebase and ranks symbol definitions by how often they are
referenced, with a bias toward references coming from "hot" files. It outputs
quickfix-friendly lines for jumping to definitions.

## What it does

- Parses source files with tree-sitter.
- Finds definitions and references across files.
- Builds a file-level reference graph and computes a file rank.
- Weights references by file rank and git frecency.
- Outputs one line per definition.

## How it works

cruxlines works in two layers:

1) File graph
   - A file-level graph is built from usage file -> definition file edges.
   - PageRank is computed on this small graph to get a per-file rank.

2) Definition scoring
   - Each definition gets a local score based on how many references it has.
   - References are weighted by the rank of the file they come from.
   - If a name is defined multiple times, the score is divided by the number
     of definitions to reduce name-collision noise.
   - Final score = local_score * file_rank(definition_file).

The output includes all components so you can interpret the score.

## Heuristics (and why)

The goal is to keep logic simple and avoid heavy per-language semantics:

- Python: only top-level definitions/assignments (importable symbols).
- JavaScript/TypeScript: only exported declarations (importable symbols).
- Rust: only top-level items (importable symbols).
- References are name-based, which is fast and language-agnostic.
- Name collisions are smoothed by splitting score across same-name definitions.

These heuristics are not semantically perfect, but they keep complexity low
while producing useful rankings.

## CLI usage

Analyze the current repo (run from the repo root):

```
cruxlines
```

Filter by ecosystem (defaults to all):

```
cruxlines --ecosystem python
```

Shorthand aliases are supported (`py`, `js`, `ts`, `tsx`, `rs`):

```
cruxlines -e py
```

Java/Kotlin use the `java` ecosystem (alias `jvm`):

```
cruxlines -e java
```

Include score metadata in the output:

```
cruxlines --metadata
```

## Library usage

Use the library API by passing a repo root and selected ecosystems:

```rust
use std::collections::HashSet;
use std::path::PathBuf;

use cruxlines::{cruxlines, Ecosystem};

let repo_root = PathBuf::from(".");
let ecosystems = HashSet::from([Ecosystem::Python, Ecosystem::JavaScript]);
let rows = cruxlines(&repo_root, &ecosystems)?;
```

## Output format

Each line matches the Vim quickfix format and includes the definition line:

```
path:line:col: <line>
```

With `--metadata`, the message includes the scoring fields:

```
path:line:col: rank=... local=... file=... name=... | <line>
```
Reference detection is heuristic and may include false positives.

## Supported languages

- Java (`.java`)
- Python (`.py`)
- JavaScript (`.js`, `.jsx`)
- TypeScript (`.ts`, `.tsx`)
- Kotlin (`.kt`, `.kts`)
- Rust (`.rs`)

## Git ignore behavior

- Directory scans respect gitignore and common ignore files.

## Repo root

cruxlines expects to run from the repository root (a directory with `.git`) and
always scans the whole repo.

## Notes

cruxlines uses git history to compute frecency for files via the `frecenfile`
crate. If no git repository is found, frecency defaults to neutral weighting.
