README.md

# RunOrComp

Elixir compile-time detection via compiler tracing. Produces a JSON database
that editor plugins can use to highlight code that runs at compile time vs runtime.

Includes a Neovim plugin that highlights compile-time lines with a subtle
background tint and virtual text labels.

## How it works

RunOrComp uses Elixir's [compilation tracer](https://hexdocs.pm/elixir/Code.html#module-compilation-tracers)
to observe which code constructs execute at compile time:

- **Macro calls** from non-stdlib dependencies (e.g., `Plug.Builder.plug/1`)
- **Module-level function calls** (e.g., `Mix.env/0`, `Application.compile_env/3`)
- **Compile-time callbacks** — dynamically discovered by scanning dependency
  source for `__before_compile__` macros and the callbacks they invoke
  (e.g., `Plug.Builder` calls `init/1` at compile time)

Standard library modules, Kernel constructs, and language plumbing are filtered
out so only meaningful compile-time indicators remain.

## Setup

Add `runorcomp` to your project's dependencies:

```elixir
defp deps do
  [
    {:runorcomp, "~> 0.1.0", only: [:dev, :test], runtime: false}
  ]
end
```

Then configure the tracer and compiler in your project:

```elixir
def project do
  [
    compilers: Mix.compilers() ++ [:runorcomp],
    elixirc_options: [tracers: [Runorcomp.Tracer]],
    # ...
  ]
end
```

The tracer runs during `mix compile` and the compiler writes the database to
`_build/{env}/runorcomp.json` after each compilation pass. Incremental
compilation is supported — only recompiled files are re-traced, and existing
data for unchanged files is preserved.

Note: `.exs` files (like `mix.exs` or test support files) are not traced —
only `.ex` files compiled by `mix compile` are included.

## Neovim plugin

The included Neovim plugin reads the JSON database and highlights compile-time
lines with a subtle background tint and optional virtual text labels.

### Installation (lazy.nvim)

```lua
{
  "dbernheisel/runorcomp",
  ft = "elixir",
  config = function()
    vim.api.nvim_set_hl(0, "RunorcompCompileTime", { bg = "#1a1a2e" })
    vim.api.nvim_set_hl(0, "RunorcompLabel", { fg = "#6e6ea8", italic = true })
    require("runorcomp").setup()
  end,
}
```

### Commands

- `:RunorcompRefresh` — re-read the database and update highlights
- `:RunorcompClear` — remove all highlights
- `:RunorcompToggleLabels` — toggle virtual text labels on/off

### Options

```lua
require("runorcomp").setup({
  virtual_text = true, -- show "← target" labels (default: true)
})
```

### Highlight groups

| Group | Default | Purpose |
|-------|---------|---------|
| `RunorcompCompileTime` | links to `CursorLine` | Background tint on compile-time lines |
| `RunorcompLabel` | links to `Comment` | Virtual text label color |

Compile-time callbacks (like `init/1` called by `Plug.Builder`) highlight the
entire function body, not just the `def` line.